NEERC-2017

A. Archery Tournament

用线段树套set维护横坐标区间内的所有圆,查询时在$O(\log n)$个set中二分查找即可。

时间复杂度$O(n\log^2n)$。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
#define rt 1,1,g
#define mid (l+r>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 2e6 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
struct AAA
{
int y, x;
}a[N];
LL K(LL x)
{
return x * x;
}
bool in_circle(int o1, int o2)
{
int y1 = a[o1].y;
int x1 = a[o1].x;
int y2 = a[o2].y;
int x2 = a[o2].x;
return K(y1 - y2) + K(x1 - x2) < K(y2);
}
struct A
{
int ask;
int id;
bool operator < (const A & b)const
{
if(ask && b.ask)
{
if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
else return id < b.id;
}
else if(!ask && !b.ask)
{
if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
else return id < b.id;
}
else if(ask && !b.ask)
{
if(in_circle(id, b.id))return 1;
else
{
if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
else return id < b.id;
}
}
else //if(!ask && b.ask)
{
if(in_circle(b.id, id))return 0;
else
{
if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
else return id < b.id;
}
}
}
};
struct Q
{
int tp, y, x;
}q[N];
int v[N * 3]; int g;
set<A>sot[N * 4];
void build(int o, int l, int r)
{
sot[o].clear();
if(l == r)
{
return;
}
build(lson);
build(rson);
}
int O, L, R;
void ins(int o, int l, int r)
{
if(L <= l && r <= R)
{
sot[o].insert({0, O});
return;
}
if(L <= mid)ins(lson);
if(R > mid)ins(rson);
}
void del(int o, int l, int r)
{
if(L <= l && r <= R)
{
sot[o].erase({0, O});
return;
}
if(L <= mid)del(lson);
if(R > mid)del(rson);
}
int P;
int find(int o, int l, int r)
{
auto it = sot[o].lower_bound({1, 0});
if(it != sot[o].end())
{
int aim = it->id;
if(in_circle(0, aim))return aim;
}
if(l == r)return 0;
if(P <= mid)return find(lson);
else return find(rson);
}
int main()
{
while(~scanf("%d", &n))
{
g = 0;
for(int i = 1; i <= n; ++i)
{
scanf("%d%d%d", &q[i].tp, &q[i].x, &q[i].y);
if(q[i].tp == 1)
{
q[i].tp = i;
a[i].y = q[i].y; a[i].x = q[i].x;
v[++g] = q[i].x - q[i].y;
v[++g] = q[i].x + q[i].y;
}
else
{
q[i].tp = 0;
v[++g] = q[i].x;
}
}
sort(v + 1, v + g + 1);
g = unique(v + 1, v + g + 1) - v - 1;
build(rt);
for(int i = 1; i <= n; ++i)
{
if(q[i].tp)
{
O = q[i].tp;
L = lower_bound(v + 1, v + g + 1, q[i].x - q[i].y) - v + 1;
R = lower_bound(v + 1, v + g + 1, q[i].x + q[i].y) - v - 1;
if(L <= R)
{
ins(rt);
}
}
else
{
P = lower_bound(v + 1, v + g + 1, q[i].x) - v;
a[0].y = q[i].y; a[0].x = q[i].x;
O = find(rt);
if(O)
{
printf("%d\n", O);
L = lower_bound(v + 1, v + g + 1, q[O].x - q[O].y) - v + 1;
R = lower_bound(v + 1, v + g + 1, q[O].x + q[O].y) - v - 1;
del(rt);
}
else puts("-1");
}
}
}
return 0;
}
/*
【trick&&吐槽】
4
1 0 12
1 24 10
1 12 3
2 16 14 8
1 0 12
2 -11 22
1 24 10
1 12 3
2 12 12
2 16 14
1 28 15
2 3 6 【题意】 【分析】 【时间复杂度&&优化】 */

  

B. Box

分类讨论。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int a[3];
int w, h;
int ww, hh;
bool check4()
{
return ww <= w && hh <= h;
}
bool check3()
{
//1
ww = a[0] * 0 + a[1] * 2 + a[2] * 2;
hh = a[0] * 1 + a[1] * 0 + a[2] * 2;
if(check4())return 1; //2
ww = a[0] * 0 + a[1] * 2 + a[2] * 2;
hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
if(check4())return 1; //3
ww = a[0] * 1 + a[1] * 1 + a[2] * 3;
hh = a[0] * 1 + a[1] * 1 + a[2] * 0;
if(check4())return 1; //4
ww = a[0] * 1 + a[1] * 1 + a[2] * 2;
hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
if(check4())return 1; //5
ww = a[0] * 1 + a[1] * 2 + a[2] * 1;
hh = a[0] * 1 + a[1] * 0 + a[2] * 2;
if(check4())return 1; //6
ww = a[0] * 2 + a[1] * 1 + a[2] * 1;
hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
if(check4())return 1; //7
ww = a[0] * 2 + a[1] * 1 + a[2] * 0;
hh = a[0] * 1 + a[1] * 1 + a[2] * 2;
if(check4())return 1; return 0;
}
bool check2()
{
sort(a, a + 3);
do
{
if(check3())return 1;
}while(next_permutation(a, a + 3));
return 0;
}
bool check()
{
if(check2())return 1;
swap(w, h);
if(check2())return 1;
else return 0;
}
int main()
{
while(~scanf("%d%d%d", &a[0], &a[1], &a[2]))
{
scanf("%d%d", &w, &h);
puts(check() ? "Yes" : "No");
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */

  

C. Connections

考虑强连通分量的Kosaraju算法,会发现只有$2(n-1)$条边是有用的,符合题目中保留$2n$条边要求。

#include<cstdio>
const int N=300010;
int Case,n,m,i,x,y,cnt,use[N],g[2][N],nxt[2][N],v[2][N],ed,q[N],t,vis[N],e[N][2];
inline void add(int x,int y){
v[0][++ed]=y;nxt[0][ed]=g[0][x];g[0][x]=ed;
v[1][ed]=x;nxt[1][ed]=g[1][y];g[1][y]=ed;
}
void dfs1(int x){
vis[x]=1;
for(int i=g[0][x];i;i=nxt[0][i])if(!vis[v[0][i]])use[i]=1,dfs1(v[0][i]);
q[++t]=x;
}
void dfs2(int x){
vis[x]=0;
for(int i=g[1][x];i;i=nxt[1][i])if(vis[v[1][i]])use[i]=1,dfs2(v[1][i]);
}
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%d%d",&n,&m);
for(ed=0,i=1;i<=n;i++)vis[i]=g[0][i]=g[1][i]=0;
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
e[i][0]=x,e[i][1]=y;
add(x,y);
use[i]=0;
}
for(t=0,i=1;i<=n;i++)if(!vis[i])dfs1(i);
for(i=n;i;i--)if(vis[q[i]])dfs2(q[i]);
cnt=n*2;
for(i=1;i<=m;i++)if(use[i])cnt--;
for(i=1;i<=m;i++)if(!use[i]&&cnt>0)use[i]=1,cnt--;
for(i=1;i<=m;i++)if(!use[i])printf("%d %d\n",e[i][0],e[i][1]);
}
}
/*
111
4 9
1 2
1 3
2 3
2 4
3 2
3 4
4 1
4 2
4 3
*/

  

D. Designing the Toy

斜着构造然后再补充剩下部分即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int A, B, C;
int a[3];
bool v[N][N];
struct AAA
{
AAA(int x, int y, int z)
{
v[0] = x;
v[1] = y;
v[2] = z;
}
int v[3];
};
vector<AAA>vt;
void SWAP(int x, int y)
{
int g = vt.size();
for(int i = 0; i < g; ++i)
{
swap(vt[i].v[x], vt[i].v[y]);
}
}
int main()
{
while(~scanf("%d%d%d", &A, &B, &C))
{
a[0] = A;
a[1] = B;
a[2] = C;
sort(a, a + 3);
if(a[0] * a[1] < a[2])
{
puts("-1");
continue;
}
else
{
vt.clear();
MS(v, 0);
int cnt = a[2] - a[1];
for(int i = 1; i <= a[0]; ++i)
{
//vt.push_back({i, i, 1});
vt.push_back(AAA(i, i, 1));
v[i][i] = 1;
}
for(int i = a[0] + 1; i <= a[1]; ++i)
{
//vt.push_back({1, i, 1});
vt.push_back(AAA(1, i, 1));
v[1][i] = 1;
}
for(int i = 1; i <= a[0]; ++i)
{
for(int j = 1; j <= a[1]; ++j)
{
if(v[i][j] == 0 && cnt)
{
--cnt;
//vt.push_back({i, j, 1});
vt.push_back(AAA(i, j, 1));
v[i][j] = 1;
}
}
}
}
if(A >= max(B, C))
{
if(C >= B);
else SWAP(0, 1);
}
else if(C >= max(A, B))
{
SWAP(0, 2);
if(A >= B);
else SWAP(1, 2);
}
else
{
SWAP(1, 2);
if(C >= A);
else SWAP(0, 2);
}
printf("%d\n", vt.size());
for(auto it : vt)
{
printf("%d %d %d\n", it.v[0], it.v[1], it.v[2]);
}
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */

  

E. Easy Quest

依次考虑每个事件,维护每种数字出现次数和待定的数字个数,当数字不够时确定一个数字。

#include<cstdio>
const int N=100000;
int n,i,x,c[N],cnt,m,q[N];
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&x);
if(x>0)c[x]++;
else if(x==0){
cnt++;
}else{
if(c[-x])c[-x]--;
else if(cnt){
q[++m]=-x;
cnt--;
}else return puts("No"),0;
}
}
puts("Yes");
for(i=1;i<=m;i++)printf("%d ",q[i]);
while(cnt--)printf("1 ");
}

  

F. The Final Level

贪心选离目的地较近的那一维坐标靠近即可。

G. The Great Wall

二分答案,转化为统计有多少方案的权值和不超过$mid$。

整理出式子后可以通过排序后双指针+树状数组维护。

时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=30010;
int n,len,i;
int m;
ll K,a[N],b[N],c[N],L,R,ANS,MID;
ll f[N],g[N];
int q[N],p[N],bit[N];
inline bool cmp1(int x,int y){return f[x]<f[y];}
inline bool cmp2(int x,int y){return g[x]<g[y];}
inline void add(int x){for(;x<=n;x+=x&-x)bit[x]++;}
inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
inline int sum(int l,int r){
l=max(l,1);
r=min(r,n);
if(l>r)return 0;
return ask(r)-ask(l-1);
}
ll cal(){
int i,j;
m=n-len+1;
for(i=1;i<=m;i++){
f[i]=a[i-1]+b[i+len-1]-b[i-1]-a[i+len-1];
q[i]=i;
}
sort(q+1,q+m+1,cmp1);
ll ret=0;
for(i=1;i<=n;i++)bit[i]=0;
for(i=m,j=1;i;i--){
while(j<=m&&f[q[i]]+f[q[j]]<=MID)add(q[j++]);
ret+=sum(q[i]+len,m);
}
for(i=1;i<=m;i++){
f[i]=a[i-1]-b[i-1]+c[i+len-1]-b[i+len-1];
g[i]=b[i-1]-c[i-1]+b[i+len-1]-a[i+len-1];
q[i]=p[i]=i;
}
sort(q+1,q+m+1,cmp1);
sort(p+1,p+m+1,cmp2);
for(i=1;i<=n;i++)bit[i]=0;
for(i=m,j=1;i;i--){
while(j<=m&&f[q[i]]+g[p[j]]<=MID)add(p[j++]);
ret+=sum(q[i]+1,q[i]+len-1);
}
return ret;
}
int main(){
scanf("%d%d%lld",&n,&len,&K);
for(i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-1];
for(i=1;i<=n;i++)scanf("%lld",&b[i]),b[i]+=b[i-1];
for(i=1;i<=n;i++)scanf("%lld",&c[i]),c[i]+=c[i-1];
L=0,R=c[n];
while(L<=R){
MID=(L+R)>>1;
ll tmp=cal();
if(tmp>=K)R=(ANS=MID)-1;else L=MID+1;
}
printf("%lld",ANS+a[n]);
}
/*
4 2 3
1 2 3 4
3 3 5 5
7 7 7 7
*/

  

H. Hack

留坑。

I. Interactive Sort

考虑将偶数划分成若干不可区分大小的集合,将这些集合从小到大排序。一开始所有偶数形成一个不可区分大小的集合。

依次考虑每个奇数,将其在这些集合中二分查找,从对应集合中任取一个数进行比较,得到它大约落在哪两个集合中,再暴力遍历两个集合中所有数字,将对应集合划分成两半。同时,这个过程可以得出有多少偶数小于当前奇数,故可以确定出该奇数。

那么考虑完所有奇数后,所有偶数也就排好了序,因为数据随机,因此可以认为每次都是均分的,比较次数$O(n\log n)$。

#include<cstdio>
#include<vector>
using namespace std;
const int N=11111,K=2;
int n,m,i,j,k;
int cnt;
int cp;
vector<int>a[N];
int fin[N];
int q[N];
//+ -
vector<int>ans;
inline bool cmp(int x,int y){//x<y?
if(x>0){
printf("? %d %d\n",x,-y);
fflush(stdout);
char op[9];
scanf("%s",op);
return op[0]=='<';
}else{
printf("? %d %d\n",y,-x);
fflush(stdout);
char op[9];
scanf("%s",op);
return op[0]=='>';
}
}
int flag,c0,c1;
int result[N];
int num[N];
inline void gao(int x,int o){
c0=c1=0;
int cur=a[q[x]].size();
for(int i=0;i<cur;i++){
int y=a[q[x]][i];
num[i]=y;
result[i]=cmp(y,o);
if(result[i]){
c0++;
}else{
c1++;
}
}
if(!c1){
flag=1;
return;
}
if(!c0){
flag=-1;
return;
}
flag=0;
cp++;
for(int i=cp;i>x+1;i--)q[i]=q[i-1];
q[x+1]=++cnt;
a[cnt].clear();
a[q[x]].clear();
for(int i=0;i<cur;i++)if(result[i])a[q[x]].push_back(num[i]);
else a[cnt].push_back(num[i]);
}
inline void gao2(int x,int o){
int t=cmp(a[q[x]][0],o);
if(t){
flag=1;
return;
}else{
flag=-1;
return;
}
}
int main(){
scanf("%d",&n);
if(n==1){
puts("! 1");
fflush(stdout);
return 0;
}
if(n==2){
puts("! 2 1");
fflush(stdout);
return 0;
}
//even
//odd
m=n/2; //use odd to sort even
cnt=1;
cp=1;
a[1].clear();
for(i=1;i<=m;i++)a[1].push_back(i);
q[1]=1;
for(i=1;i<=n-m;i++){
int l=1,r=cp;
while(l+K<=r){
int mid=(l+r)>>1;
gao2(mid,-i);
if(flag<0)r=mid;else l=mid;
}
while(l<=r){
int mid=(l+r)>>1;
gao(mid,-i);
if(flag==0)break;
if(flag<0)r=mid-1;else l=mid+1;
}
l=max(l-2,1);
while(l<=cp){
gao2(l,-i);
if(flag>0)l++;else break;
}
int res=0;
for(j=1;j<l;j++)res+=a[q[j]].size();
fin[m+i]=res*2+1;
}
int k=0;
for(i=1;i<=cp;i++){
for(j=0;j<a[q[i]].size();j++){
k+=2;
fin[a[q[i]][j]]=k;
}
} printf("!");
for(i=1;i<=n;i++)printf(" %d",fin[i]);
puts("");
fflush(stdout);
}

  

J. Journey from Petersburg to Moscow

若经过至多$k$条边,则答案显然包含在$1$到$n$直接的最短路之中。

否则至少经过$k$条边,枚举最大$k$条边中最小的那一条边的权值$x$,将所有边权值重置为$\max(0,w-x)$,求出$1$到$n$的最短路$d$,则可以用$d+kx$更新答案。这是因为如果此时求出的最短路$d$中边数不够$k$,那么$d+kx$必然不优;而如果收费的边超过$k$条,则减去的$x$过小,也会造成答案不优,因此一定存在一个$x$使得刚好取到最优解。

时间复杂度$O(m^2\log m)$。

#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,int>P;
const int N=3010;
const ll inf=1LL<<60;
int n,m,K,i,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed;
int lim,W;
ll d[N];
ll ans;
priority_queue<P,vector<P>,greater<P> >q;
inline void add(int x,int y,int z){
v[++ed]=y;
w[ed]=z;
nxt[ed]=g[x];
g[x]=ed;
}
struct E{int x,y,z;}e[N];
inline bool cmp(const E&a,const E&b){return a.z<b.z;}
inline void ext(int x,ll y){
if(d[x]>y){
q.push(P(d[x]=y,x));
}
}
inline void dij(){
int i,j;
for(i=1;i<=n;i++)d[i]=inf;
ext(1,0);
while(!q.empty()){
P t=q.top();q.pop();
if(d[t.second]<t.first)continue;
for(int i=g[t.second];i;i=nxt[i]){
ext(v[i],t.first+max(w[i]-W,0));
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&K);
for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
sort(e+1,e+m+1,cmp);
ed=1;
for(i=1;i<=m;i++)add(e[i].x,e[i].y,e[i].z),add(e[i].y,e[i].x,e[i].z);
dij();
ans=d[n];
for(lim=1;lim<=m;lim++){
W=e[lim].z;
dij();
ans=min(ans,d[n]+1LL*W*K);
}
printf("%lld",ans);
}

  

K. Knapsack Cryptosystem

留坑。

L. Laminar Family

首先将所有未被任何一条树链经过的树边删除,那么剩下的点度数都不能超过$2$,否则必然非法。

那么剩下的图每个连通块都只可能是链,是经典序列问题,把所有区间按左端点排序后单调栈判断即可。

时间复杂度$O(f\log n)$。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=100010;
int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
int f[N],son[N],size[N],top[N],d[N];
int e[N][2];
int tag[N];
int deg[N];
int G[N],V[N<<1],NXT[N<<1],ED;
bool vis[N];
int ge[N],vv[N],nxte[N],ee;
void NIE(){
puts("No");
exit(0);
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline void adde(int x,int y){vv[++ee]=y;nxte[ee]=ge[x];ge[x]=ee;}
void dfs(int x){
d[x]=d[f[x]]+1;
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x;
dfs(v[i]);
size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
}
inline void addedge(int x,int y){
//printf("! %d %d\n",x,y);
deg[x]++;deg[y]++;
V[++ED]=y;NXT[ED]=G[x];G[x]=ED;
V[++ED]=x;NXT[ED]=G[y];G[y]=ED;
}
void dfs3(int x){
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
dfs3(v[i]);
tag[x]+=tag[v[i]];
}
if(x>1&&tag[x])addedge(x,f[x]);
}
inline int lca(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
x=f[top[x]];
}
return d[x]<d[y]?x:y;
}
int q[N],pos[N];
int all;
struct Seg{
int l,r;
}seg[N],st[N];
inline bool cmp(const Seg&a,const Seg&b){
if(a.l!=b.l)return a.l<b.l;
return a.r>b.r;
}
inline void append(int l,int r){
if(l>r)swap(l,r);
seg[++all].l=l;
seg[all].r=r;
}
inline void check(){
if(all<=1)return;
sort(seg+1,seg+all+1,cmp);
int i;
int t=0;
for(i=1;i<=all;i++){
while(t){
if(seg[i].r<=st[t].r)break;
if(seg[i].l<=st[t].r)NIE();
t--;
}
st[++t]=seg[i];
}
}
inline void solve(int S){
int cnt=0;
int i,j;
while(1){
vis[S]=1;
q[++cnt]=S;
int t=0;
for(i=G[S];i;i=NXT[i])if(!vis[V[i]]){
t=V[i];
}
if(!t)break;
S=t;
}
//for(i=1;i<=cnt;i++)printf("%d ",q[i]);puts("");
for(i=1;i<=cnt;i++)pos[q[i]]=i;
all=0;
for(i=1;i<=cnt;i++){
for(j=ge[q[i]];j;j=nxte[j]){
append(pos[q[i]],pos[vv[j]]);
}
}
check();
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1);
dfs2(1,1);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
e[i][0]=x,e[i][1]=y;
int z=lca(x,y);
tag[x]++;
tag[y]++;
tag[z]-=2;
adde(x,y);
}
dfs3(1);
for(i=1;i<=n;i++)if(deg[i]>2)NIE();
for(i=1;i<=n;i++)if(deg[i]==1&&!vis[i])solve(i);
puts("Yes");
}
/*
4 2
1 2
2 3
2 4
1 2
4 2 6 5
1 2
2 3
3 4
5 6
5 2
2 1
6 6
1 4
3 4
4 1
*/
上一篇:实现PHPCMS手机门户的伪静态


下一篇:jQuery的文档操作