BZOJ4771: 七彩樹
阿新 • • 發佈:2018-10-08
之間 add sub n-1 i節點 esc nbsp \n sum
Submit: 1520 Solved: 432
[Submit][Status][Discuss]
5 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1
2
3
1
1
2
1
1
題解: 對於每個節點 他只會對這個節點到根這條路徑上的點產生貢獻 所以我們考慮樹鏈的並 找到每個節點能作用的深度最低的位置 然後對於深度建主席樹,權值為dfs序的下標 通過set來維護樹鏈的並 最後查詢即可
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar(); return x*f; } typedef struct node{ int l,r,sum; }node; node d[MAXN*81]; int f[MAXN][21],dep[MAXN],p[MAXN],fp[MAXN],cnt,cnt1,rt[MAXN],a[MAXN],n,q,num[MAXN],id[MAXN]; set<int>s[MAXN]; set<int>::iterator ite,ip; void dfs(int x,int fa,int deep){ f[x][0]=fa;dep[x]=deep+1;p[x]=++cnt;fp[p[x]]=x;num[x]=1; link(x){ if(j->t!=fa)dfs(j->t,x,deep+1),num[x]+=num[j->t]; } } void dfs1(int x){ for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1]; link(x)if(j->t!=f[x][0])dfs1(j->t); } int Lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); int tmp=dep[u]-dep[v]; inc(i,0,20)if(tmp&(1<<i))u=f[u][i]; if(u==v)return u; dec(i,20,0){ if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i]; } return f[u][0]; } void update(int &x,int y,int l,int r,int t,int vul){ x=++cnt1;d[x]=d[y];d[x].sum+=vul; if(l==r)return ; int mid=(l+r)>>1; if(t<=mid)update(d[x].l,d[y].l,l,mid,t,vul); else update(d[x].r,d[y].r,mid+1,r,t,vul); } int ans; void querty(int x,int y,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ans+=d[y].sum-d[x].sum;return ;} int mid=(l+r)>>1; if(ql<=mid)querty(d[x].l,d[y].l,l,mid,ql,qr); if(qr>mid)querty(d[x].r,d[y].r,mid+1,r,ql,qr); } bool cmp(int aa,int bb){return dep[aa]<dep[bb];} int main(){ int _=read(); while(_--){ cnt=cnt1=0;n=read();q=read();memset(e,0,sizeof(e));memset(h,0,sizeof(h));o=e; inc(i,1,n)id[i]=i,a[i]=read(),s[i].clear(); int u,v; inc(i,2,n)u=read(),add(i,u),add(u,i); dfs(1,0,0);dfs1(1); sort(id+1,id+n+1,cmp); int tot=1; inc(i,1,n){ rt[i]=++cnt1;d[rt[i]]=d[rt[i-1]]; while(tot<=n&&dep[id[tot]]<=i){ update(rt[i],rt[i],1,n,p[id[tot]],1); ite=s[a[id[tot]]].lower_bound(p[id[tot]]); int x=0,y=0; if(ite!=s[a[id[tot]]].begin())ip=ite,ip--,x=fp[(*ip)],update(rt[i],rt[i],1,n,p[Lca(id[tot],x)],-1); if(ite!=s[a[id[tot]]].end())ip=ite,y=fp[(*ip)],update(rt[i],rt[i],1,n,p[Lca(id[tot],y)],-1); if(x&&y)update(rt[i],rt[i],1,n,p[Lca(x,y)],1); s[a[id[tot]]].insert(p[id[tot]]);tot++; } } int res=0,x,d; while(q--){ x=read()^res;d=read()^res; ans=0;querty(rt[dep[x]-1],rt[min(dep[x]+d,n)],1,n,p[x],p[x]+num[x]-1);res=ans; printf("%d\n",res); } } }
4771: 七彩樹
Time Limit: 5 Sec Memory Limit: 256 MBSubmit: 1520 Solved: 432
[Submit][Status][Discuss]
Description
給定一棵n個點的有根樹,編號依次為1到n,其中1號點是根節點。每個節點都被染上了某一種顏色,其中第i個節 點的顏色為c[i]。如果c[i]=c[j],那麽我們認為點i和點j擁有相同的顏色。定義depth[i]為i節點與根節點的距離 ,為了方便起見,你可以認為樹上相鄰的兩個點之間的距離為1。站在這棵色彩斑斕的樹前面,你將面臨m個問題。 每個問題包含兩個整數x和d,表示詢問x子樹裏且depth不超過depth[x]+d的所有點中出現了多少種本質不同的顏色 。請寫一個程序,快速回答這些詢問。
Input
第一行包含一個正整數T(1<=T<=500),表示測試數據的組數。 每組數據中,第一行包含兩個正整數n(1<=n<=100000)和m(1<=m<=100000),表示節點數和詢問數。 第二行包含n個正整數,其中第i個數為c[i](1<=c[i]<=n),分別表示每個節點的顏色。 第三行包含n-1個正整數,其中第i個數為f[i+1](1<=f[i]<i),表示節點i+1的父親節點的編號。 接下來m行,每行兩個整數x(1<=x<=n)和d(0<=d<n),依次表示每個詢問。 輸入數據經過了加密,對於每個詢問,如果你讀入了x和d,那麽真實的x和d分別是x xor last和d xor last, 其中last表示這組數據中上一次詢問的答案,如果這是當前數據的第一組詢問,那麽last=0。 輸入數據保證n和m的總和不超過500000。
Output
對於每個詢問輸出一行一個整數,即答案。
Sample Input
15 8
1 3 3 2 2
1 1 3 3
1 0
0 0
3 0
1 3
2 1
2 0
6 2
4 1
Sample Output
12
3
1
1
2
1
1
BZOJ4771: 七彩樹