嗯。。。企图做ZJOI2011,结果一题都不会QAQ。生气的写树剖来了~
这题暴力的树剖是可以的,但我是在黄学长那找了这题,他好像有个非常妙的做法,现在差不多要去打ball了,之后再学习一下吧。
树剖:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #include<string> #include<ctime> #include<queue> #include<map> #include<set> #include<vector> typedef long long LL; using namespace std; const int N=300010; struct edge{int to,nxt;}e[N<<1]; struct node{int l,r,lazy;}a[N<<2]; int n,b[N],head[N],cnt,pos[N],siz[N],bel[N],fa[N]; int read() {int d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;} void judge(){freopen(".in","r",stdin); freopen(".out","w",stdout);} void addedge(int x,int y) { e[++cnt]=(edge){y,head[x]}; head[x]=cnt; e[++cnt]=(edge){x,head[y]}; head[y]=cnt; } void dfs(int u) { siz[u]=1; for (int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if (v==fa[u]) continue; fa[v]=u; dfs(v); siz[u]+=siz[v]; } } void dfs2(int u,int Bel) { pos[u]=++cnt; bel[u]=Bel; int x=0; for (int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if (v==fa[u]) continue; if (siz[v]>siz[x]) x=v; } if (!x) return; dfs2(x,Bel); for (int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if (v==fa[u]||v==x) continue; dfs2(v,v); } } void pushdown(int k) { if (!a[k].lazy) return; int k1=k<<1,k2=k1|1; a[k1].lazy+=a[k].lazy; a[k2].lazy+=a[k].lazy; a[k].lazy=0; } void build(int k,int l,int r) { a[k]=(node){l,r,0}; if (l==r) return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void update(int k,int l,int r,int v) { if (l<=a[k].l&&a[k].r<=r) {a[k].lazy+=v; return;} pushdown(k); int mid=(a[k].l+a[k].r)>>1; if (r<=mid) update(k<<1,l,r,v); else if (l>mid) update(k<<1|1,l,r,v); else update(k<<1,l,mid,v),update(k<<1|1,mid+1,r,v); } int ask(int k,int x) { if (a[k].l==a[k].r) return a[k].lazy; pushdown(k); int mid=(a[k].l+a[k].r)>>1; if (x<=mid) return ask(k<<1,x); else return ask(k<<1|1,x); } int main() { //judge(); n=read(); for (int i=1;i<=n;i++) b[i]=read(); for (int i=1;i<n;i++) addedge(read(),read()); dfs(1); cnt=0; dfs2(1,1); build(1,1,n); int x=b[1]; for (int i=2;i<=n;i++) { int y=b[i]; while (bel[x]!=bel[y]) { if (pos[x]<pos[y]) swap(x,y); update(1,pos[bel[x]],pos[x],1); x=fa[bel[x]]; } if (pos[x]>pos[y]) swap(x,y); update(1,pos[x],pos[y],1); x=b[i]; update(1,pos[x],pos[x],-1); } for (int i=1;i<=n;i++) printf("%d\n",ask(1,pos[i])); return 0; }
未完待续...
摘自黄学长:http://hzwer.com/4522.html
其实是可以直接上树链剖分的
但是我们发现这道题只要实现每次将u-v路径的点权+1
只要在u和v上打个+1标记,lca(u,v)和lca(u,v)->fa打-1标记,最后dp上传标记即可
本质是个差分。。。
代码就不写了~\(≧▽≦)/~啦啦啦
完结~