11.03T2 树链剖分
5956 -- 【模拟试题】相交
Description
给你一棵树,每次询问树上两条链是否有交点。
Input
第一行n,表示n个结点
第二行开始n-1行俩个·数x y,表示x,y有一条边
接下来q,表示q个询问
接下来q行四个数a b c d,询问a到b的链是否与c到d的链有交点
第二行开始n-1行俩个·数x y,表示x,y有一条边
接下来q,表示q个询问
接下来q行四个数a b c d,询问a到b的链是否与c到d的链有交点
Output
输出Q行(YES或NO)
Sample Input
输入1:
8
1 2
1 3
2 4
2 5
5 6
5 7
3 8
4
2 5 4 3
5 3 8 8
5 4 6 7
4 8 6 7
输入2:
15
2 1
3 1
4 2
5 3
6 2
7 2
8 5
9 3
10 6
11 5
12 7
13 11
14 1
15 1
5
1 2 3 4
4 7 1 9
2 3 7 9
2 6 7 8
2 1 6 8
Sample Output
输出1:
YES
NO
YES
NO
输出2:
YES
NO
YES
YES
YES
Hint
30%的数据1≤n,q≤3000
另外20%数据是一条链
100%的数据1≤n,q≤100000
另外20%数据是一条链
100%的数据1≤n,q≤100000
题意:给你一棵树,每次询问树上两条链是否有交点。
30% 将第一条链上所有点打上标记,再遍历第二条链,查看第二条链上是 否有打上标记的点。
另外 20% 树退化为一条链,每次询问等价于查询数轴上两条线段是否相交。 100% 仔细观察不难发现,两条树链相交的充要条件是其中一条路径的顶点 在另一条路径上,每次询问求出 lca 判断即可。
管他什么正解,直接上树链剖分
code:
1 #include<iostream> 2 #include<cstdio> 3 #define N 1000006 4 #define lc (p<<1) 5 #define rc (p<<1|1) 6 using namespace std; 7 struct node{ 8 int u,v; 9 }e[N]; 10 int first[N],nxt[N],cnt; 11 void add(int u,int v){ 12 e[++cnt].u=u; 13 e[cnt].v=v; 14 nxt[cnt]=first[u]; 15 first[u]=cnt; 16 } 17 struct T{ 18 int l,r,sum,lazy; 19 }t[N]; 20 void pushup(int p){ 21 t[p].sum=t[lc].sum+t[rc].sum; 22 } 23 void pushnow(int p,int v){ 24 t[p].sum+=(t[p].r-t[p].l+1)*v; 25 t[p].lazy+=v; 26 } 27 void pushdown(int p){ 28 if(t[p].lazy){ 29 pushnow(lc,t[p].lazy); 30 pushnow(rc,t[p].lazy); 31 t[p].lazy=0; 32 } 33 } 34 void build(int p,int l,int r){ 35 t[p].l=l,t[p].r=r; 36 if(l==r){ 37 t[p].sum=0; 38 t[p].lazy=0; 39 return; 40 } 41 int mid=l+r>>1; 42 build(lc,l,mid); 43 build(rc,mid+1,r); 44 pushup(p); 45 } 46 void update(int p,int ql,int qr,int v){ 47 if(ql<=t[p].l&&t[p].r<=qr){ 48 pushnow(p,v); 49 return; 50 } 51 pushdown(p); 52 int mid=t[p].l+t[p].r>>1; 53 if(ql<=mid)update(lc,ql,qr,v); 54 if(qr>mid)update(rc,ql,qr,v); 55 pushup(p); 56 } 57 int query(int p,int ql,int qr){ 58 if(ql<=t[p].l&&t[p].r<=qr){ 59 return t[p].sum; 60 } 61 int ans=0; 62 pushdown(p); 63 int mid=t[p].l+t[p].r>>1; 64 if(ql<=mid)ans+=query(lc,ql,qr); 65 if(qr>mid)ans+=query(rc,ql,qr); 66 pushup(p); 67 return ans; 68 } 69 int siz[N],hson[N],fa[N],dep[N]; 70 void dfs1(int x){ 71 siz[x]=1; 72 hson[x]=0; 73 for(int i=first[x];i;i=nxt[i]){ 74 int v=e[i].v; 75 if(v==fa[x])continue; 76 fa[v]=x; 77 dep[v]=dep[x]+1; 78 dfs1(v); 79 siz[x]+=siz[v]; 80 if(!hson[x]||siz[hson[x]]<siz[v])hson[x]=v; 81 } 82 } 83 int top[N],num[N],pre[N],tot; 84 void dfs2(int x,int tp){ 85 top[x]=tp; 86 num[x]=++tot; 87 pre[tot]=x; 88 if(hson[x])dfs2(hson[x],tp); 89 for(int i=first[x];i;i=nxt[i]){ 90 int v=e[i].v; 91 if(v==fa[x]||v==hson[x])continue; 92 dfs2(v,v); 93 } 94 } 95 void modify(int x,int y,int v){ 96 while(top[x]!=top[y]){ 97 if(dep[top[x]]<dep[top[y]])swap(x,y); 98 update(1,num[top[x]],num[x],v); 99 x=fa[top[x]]; 100 } 101 if(dep[x]<dep[y])swap(x,y); 102 update(1,num[y],num[x],v); 103 } 104 int ask_sum(int x,int y){ 105 int ans=0; 106 while(top[x]!=top[y]){ 107 if(dep[top[x]]<dep[top[y]])swap(x,y); 108 ans+=query(1,num[top[x]],num[x]); 109 x=fa[top[x]]; 110 } 111 if(dep[x]<dep[y])swap(x,y); 112 ans+=query(1,num[y],num[x]); 113 return ans; 114 } 115 int read(){ 116 int x=0,f=1; 117 char c=getchar(); 118 while(!isdigit(c)){ 119 if(c=='-')f=-1; 120 c=getchar(); 121 } 122 while(isdigit(c)){ 123 x=(x<<1)+(x<<3)+c-'0'; 124 c=getchar(); 125 } 126 return x*f; 127 } 128 int main(){ 129 int n; 130 n=read(); 131 for(int i=1;i<n;i++){ 132 int u,v; 133 u=read(),v=read(); 134 add(u,v); 135 add(v,u); 136 } 137 dfs1(1); 138 dfs2(1,1); 139 build(1,1,n); 140 int m; 141 m=read(); 142 for(int i=1;i<=m;i++){ 143 int a,b,c,d; 144 a=read(),b=read(),c=read(),d=read(); 145 modify(a,b,1); 146 if(ask_sum(c,d))cout<<"YES"<<'\n'; 147 else cout<<"NO"<<'\n'; 148 modify(a,b,-1); 149 } 150 } 151 //调试语句注意
over