SPOJ COT2 Count on a tree II(路径树上莫队)
2018-01-05 15:25
330 查看
题目链接
分析:
在莫队介绍中,我提到了路径树上莫队要怎么搞
dfs的过程不必冗述
对于询问,我们需要分类讨论(按照LCA的位置)
LCA一定要用倍增求
整个代码中比较玄妙的就是update:
实际上就是如果一个结点在序列出现了奇数次,那么+1
如果出现了偶数次,那么-1
于是我就YY了另一种写法(也是可以A的,而且更好理解)
wtf???
分析:
在莫队介绍中,我提到了路径树上莫队要怎么搞
dfs的过程不必冗述
对于询问,我们需要分类讨论(按照LCA的位置)
LCA一定要用倍增求
整个代码中比较玄妙的就是update:
void update(int x,int z) { int co=C[x]; num-=(bool)cnt[co]; cnt[co]-=vis[x]&1; vis[x]+=z; cnt[co]+=vis[x]&1; num+=(bool)cnt[co]; }
实际上就是如果一个结点在序列出现了奇数次,那么+1
如果出现了偶数次,那么-1
于是我就YY了另一种写法(也是可以A的,而且更好理解)
void update(int x) { int co=C[x],z; if (!vis[x]) vis[x]=1,z=1; else vis[x]=0,z=-1; if (cnt[co]==0&&z==1) num++; //注意语句顺序 cnt[co]+=z; if (cnt[co]==0) num--; }
tip
前两遍WA了,把数组开大了一点就A了wtf???
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; const int N=200010; const int M=100010; struct node{ int x,y,nxt; }; node way[N<<1]; int st ,n,m,tot=0,C ,V ,deep ,lg; int s ,e ,S[N<<1],tt=0,pre [20],num,ans ; int cnt ,vis ; struct po{ int x,y,id,block,type; }; po Q[M]; int cmp(const po &a,const po &b) { if (a.block!=b.block) return a.block<b.block; else return a.y<b.y; } void add(int u,int w) { tot++; way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot; tot++; way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot; } void dfs(int now,int fa,int dep) { pre[now][0]=fa; deep[now]=dep; S[++tt]=now; s[now]=tt; for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa) dfs(way[i].y,now,dep+1); S[++tt]=now; e[now]=tt; } int LCA(int u,int w) { if (deep[u]>deep[w]) swap(u,w); int d=deep[w]-deep[u]; if (d) for (int i=0;i<=lg&&d;i++,d>>=1) if (d&1) w=pre[w][i]; if (u==w) return u; for (int i=lg;i>=0;i--) if (pre[u][i]!=pre[w][i]) { u=pre[u][i]; w=pre[w][i]; } return pre[u][0]; } void update(int x,int z) { int co=C[x]; num-=(bool)cnt[co]; //cnt是color的出现次数 cnt[co]-=vis[x]&1; //vis是结点在序列中出现的次数 vis[x]+=z; cnt[co]+=vis[x]&1; num+=(bool)cnt[co]; } //void update(int x) //{ // int co=C[x],z; // if (!vis[x]) vis[x]=1,z=1; // else vis[x]=0,z=-1; // if (cnt[co]==0&&z==1) num++; // cnt[co]+=z; // if (cnt[co]==0) num--; //} void solve() { int L=1,R=0; num=0; for (int i=1;i<=m;i++) { while (R<Q[i].y) R++,update(S[R],1); //从右端点开始 while (R>Q[i].y) update(S[R],-1),R--; while (L<Q[i].x) update(S[L],-1),L++; while (L>Q[i].x) L--,update(S[L],1); if (Q[i].type) update(Q[i].type,1); ans[Q[i].id]=num; if (Q[i].type) update(Q[i].type,-1); } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&C[i]),V[i]=C[i]; sort(V+1,V+1+n); for (int i=1;i<=n;i++) C[i]=lower_bound(V+1,V+1+n,C[i])-V; for (int i=1;i<n;i++) { int u,w; scanf("%d%d",&u,&w); add(u,w); } dfs(1,0,1); lg=log(n)/log(2); for (int i=1;i<=lg;i++) for (int j=1;j<=n;j++) pre[j][i]=pre[pre[j][i-1]][i-1]; int unit=sqrt(n); for (int i=1;i<=m;i++) { int u,w; scanf("%d%d",&u,&w); int p=LCA(u,w); if (s[u]>s[w]) swap(u,w); if (p==u||p==w) { Q[i].x=s[u]; Q[i].y=s[w]; Q[i].id=i; Q[i].block=(Q[i].x-1)/unit+1; }else{ Q[i].x=e[u]; Q[i].y=s[w]; Q[i].id=i; Q[i].block=(Q[i].x-1)/unit+1; Q[i].type=p; } } sort(Q+1,Q+1+m,cmp); solve(); for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- [SPOJ COT2]-Count on a tree II-树上莫队
- SPOJ-COT2 Count on a tree II(树上莫队)
- spoj_cot2 Count on a tree II(树上莫队+离散化)
- [spoj COT2- Count on a tree II] 树上莫队
- 【SPOJ COT2】Count on a tree II,树上莫队
- [树上莫队] SPOJ COT2 Count on a tree II
- SPOJ COT2 Count on a tree II 树上莫队
- spoj_cot2 Count on a tree II(树上莫队+离散化)
- SPOJ10707 COT2 - Count on a tree II 【树上莫队】
- SPOJ Count on a tree II(树上莫队)
- SPOJ--Count on a tree II(树上莫队)
- SPOJ 10707 Count on a Tree II 树上莫队
- 【SPOJ】Count On A Tree II(树上莫队)
- SPOJ - COT2 : Count on a tree II (树上莫队)
- 【SPOJ10707】Count on a tree II-树上莫队算法
- SPOJ COT2 Count on a tree II [树上莫队]
- SPOJ - COT Count on a tree 树上主席树+LCA+任意路径问题
- 【spoj】【COT2 - Count on a tree II】【莫队算法】
- SPOJ COT Count on a tree(树上路径第k小 主席树)
- BZOJ 2589 Spoj 10707 Count on a tree II 强制在线莫队算法(TLE)