BZOJ 4817: [Sdoi2017]树点涂色
生活随笔
收集整理的這篇文章主要介紹了
BZOJ 4817: [Sdoi2017]树点涂色
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
4817: [Sdoi2017]樹點涂色
Time Limit:?10 Sec??Memory Limit:?128 MBSubmit:?273??Solved:?164
[Submit][Status][Discuss]
Description
Bob有一棵n個點的有根樹,其中1號點是根節點。Bob在每個點上涂了顏色,并且每個點上的顏色不同。定義一條路 徑的權值是:這條路徑上的點(包括起點和終點)共有多少種不同的顏色。Bob可能會進行這幾種操作: 1 x: 把點x到根節點的路徑上所有的點染上一種沒有用過的新顏色。 2 x y: 求x到y的路徑的權值。 3 x y: 在以x為根的子樹中選擇一個點,使得這個點到根節點的路徑權值最大,求最大權值。 Bob一共會進行m次操作Input
第一行兩個數n,m。 接下來n-1行,每行兩個數a,b,表示a與b之間有一條邊。 接下來m行,表示操作,格式見題目描述 1<=n,m<=100000Output
每當出現2,3操作,輸出一行。 如果是2操作,輸出一個數表示路徑的權值 如果是3操作,輸出一個數表示權值的最大值Sample Input
5 61 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
34
2
2 感覺自己的破題能力是不是藥丸啊,這么顯然的LCT都沒看出來…… 如果我們像lct那樣操作,一條路徑上不同顏色數就是lct中虛邊的數量+1。 那么每次多出來或者減少一條虛邊的時候就修改子樹權值就好了,這里可以先求出dfs序然后線段樹維護。 一個細節:在splay上連邊的時候,刪掉的虛邊并不是被作為右兒子那棵solay的根對應節點所在子樹,而是這棵splay的最左一個節點。 #include<cstdio> #include<algorithm> #define MN 410001 #define lp (p<<1) #define rp ((p<<1)|1) using namespace std;int read_p,read_ca; inline int read(){read_p=0;read_ca=getchar();while(read_ca<'0'||read_ca>'9') read_ca=getchar();while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar();return read_p; } struct na{int y,ne;}b[MN<<1]; int n,m,o,l[MN],num=0,x,y,fa[MN],ch[MN][2],df[MN],lo[MN],nm=0,v[MN],de[MN],ma[MN],s[MN],pdf[MN],f[MN][20]; bool rt[MN]; inline int max(int a,int b){return a>b?a:b;} inline void in(int x,int y){b[++num].y=y;b[num].ne=l[x];l[x]=num;}void rot(int k){int p=fa[k],bo=ch[p][1]==k;ch[p][bo]=ch[k][!bo];ch[k][!bo]=p;fa[ch[p][bo]]=p;fa[k]=fa[p];fa[p]=k;if (rt[p]) rt[p]=0,rt[k]=1;else ch[fa[k]][ch[fa[k]][1]==p]=k;p=k; }void splay(int x){while (!rt[x]){if (rt[fa[x]]) rot(x);elseif ((ch[fa[fa[x]]][1]==fa[x])==(ch[fa[x]][1]==x)) rot(fa[x]),rot(x);else rot(x),rot(x);} }void add(int p,int l,int r,int L,int R,int v){if (l==L&&r==R) s[p]+=v,ma[p]+=v;else{int mid=l+r>>1;if (R<=mid) add(lp,l,mid,L,R,v);elseif (L>mid) add(rp,mid+1,r,L,R,v);elseadd(lp,l,mid,L,mid,v),add(rp,mid+1,r,mid+1,R,v);ma[p]=max(ma[lp],ma[rp])+s[p];} }int ask(int p,int l,int r,int k){if (l==r) return ma[p];int mid=l+r>>1;if (k<=mid) return ask(lp,l,mid,k)+s[p];else return ask(rp,mid+1,r,k)+s[p]; }int ask(int p,int l,int r,int L,int R){if (L==l&&R==r) return ma[p];int mid=l+r>>1;if (R<=mid) return ask(lp,l,mid,L,R)+s[p];elseif (L>mid) return ask(rp,mid+1,r,L,R)+s[p];elsereturn max(ask(lp,l,mid,L,mid),ask(rp,mid+1,r,mid+1,R))+s[p]; }int lf(int x){return ch[x][0]?lf(ch[x][0]):x;}void acc(int x){for (int i=0;x;x=fa[i=x]){splay(x);if (ch[x][1]) add(1,1,nm,df[lf(ch[x][1])],lo[lf(ch[x][1])],1),rt[ch[x][1]]=1;rt[ch[x][1]=i]=0;if (ch[x][1]) add(1,1,nm,df[lf(ch[x][1])],lo[lf(ch[x][1])],-1);} }void dfs(int x){f[x][0]=fa[x];for (int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];df[x]=++nm;rt[x]=1;de[x]=de[fa[x]]+1;pdf[nm]=de[x];for (int i=l[x];i;i=b[i].ne)if (b[i].y!=fa[x]) fa[b[i].y]=x,dfs(b[i].y);lo[x]=nm; }void build(int p,int l,int r){if (l==r) {ma[p]=pdf[l];return;}int mid=l+r>>1;build(lp,l,mid);build(rp,mid+1,r);ma[p]=max(ma[lp],ma[rp]); }int lca(int x,int y){if (de[x]<de[y]) swap(x,y);for (int i=19;i>=0;i--)if (f[x][i]&&de[f[x][i]]>=de[y]) x=f[x][i];if (x==y) return x;for (int i=19;i>=0;i--)if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];return f[x][0]; }int main(){register int i;n=read();m=read();for (i=1;i<n;i++) x=read(),y=read(),in(x,y),in(y,x);dfs(1);build(1,1,n);while (m--){o=read();if (o==1) acc(read());elseif (o==2) x=read(),y=read(),o=lca(x,y),printf("%d\n",ask(1,1,n,df[x])+ask(1,1,n,df[y])-2*ask(1,1,n,df[o])+1);elsex=read(),printf("%d\n",ask(1,1,n,df[x],lo[x]));} } View Code
?
轉載于:https://www.cnblogs.com/Enceladus/p/6713473.html
總結
以上是生活随笔為你收集整理的BZOJ 4817: [Sdoi2017]树点涂色的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入SQL SERVER 2000的内存
- 下一篇: 你绝对想不到R文件找不到(cannot