題面
https://www.lydsy.com/JudgeOnline/problem.php?id=4860php
題解
點分治node
設當前重心爲vgit
假設已經把全部邊按照出發點第一關鍵字, 顏色第二關鍵字排序ide
對於當前的v 咱們順次考慮他的出邊spa
設當前出邊(v,nw) 顏色 colcode
咱們枚舉nw的出邊blog
對於一條nw的出邊而言, 分爲兩種狀況排序
1. 顏色與col相同 用線段樹維護深度及對應的最值,查詢到最大值便可 (v,nw)沒有貢獻隊列
2. 顏色與col不一樣 用另外一棵線段樹維護深度以及與(當前節點的連向其父節點的邊的顏色)不一樣的(連向子節點的邊)所對應的子節點對應的子樹以內的最值 加上col的權值get
向上的時候 將線段樹合併
Code
1 #include <cstdio> 2 #include <cctype> 3 #include <algorithm> 4 const int maxn=400010,inf=2000000010; 5 int ans,n,x,y,z,i,m,l,r,c[maxn*3],cnt; 6 inline int max(int a,int b){ 7 return a>b?a:b; 8 } 9 inline void up(int&a,const int&b){ 10 if(a<b)a=b; 11 } 12 inline int getint(){ 13 char c=getchar(); 14 int x=0,neg=1; 15 while(!isdigit(c)){ 16 if(c=='-')neg=-1; 17 c=getchar(); 18 } 19 while(isdigit(c)){ 20 x=x*10+c-48; 21 c=getchar(); 22 } 23 return x*neg; 24 } 25 struct edge{ 26 int from,to,color; 27 }e[maxn<<1]; 28 struct data{ 29 int dep,sum; 30 }; 31 struct node{ 32 int v,lc,rc; 33 }a[maxn*5]; 34 int merge(int x,int y){ 35 if(!x || !y )return x|y; 36 a[x].lc=merge(a[x].lc,a[y].lc); 37 a[x].rc=merge(a[x].rc,a[y].rc); 38 up(a[x].v,a[y].v); 39 return x; 40 } 41 void add(int&i,int rl,int rr,int x,int v){ 42 if(!i)a[i=++cnt]=(node){v,0,0}; 43 else up(a[i].v,v); 44 if(rl<rr){ 45 int m=(rl+rr)>>1; 46 if(x>m)add(a[i].rc,m+1,rr,x,v); 47 else add(a[i].lc,rl,m,x,v); 48 } 49 } 50 int query(int i,int rl,int rr,int l,int r){ 51 if(!i)return -inf; 52 if(rl==l && rr==r)return a[i].v; 53 int m=(rl+rr)>>1; 54 if(l>m)return query(a[i].rc,m+1,rr,l,r); 55 else if(r<=m)return query(a[i].lc,rl,m,l,r); 56 else return max(query(a[i].lc,rl,m,l,m),query(a[i].rc,m+1,rr,m+1,r)); 57 } 58 struct tree{ 59 int xb,h[maxn],n,size[maxn],f[maxn],rt,sum,dep[maxn],ll,ss[maxn]; 60 bool b[maxn]; 61 data w[maxn]; 62 void addedge(int x,int y,int z){ 63 e[++xb]=(edge){y,x,z}; 64 e[++xb]=(edge){x,y,z}; 65 } 66 void dfs(int x,int fa){ 67 size[x]=f[x]=1; 68 for(int i=h[x];i<h[x+1];++i){ 69 int y=e[i].to; 70 if(y!=fa && !b[y]){ 71 dfs(y,x); 72 size[x]+=size[y]; 73 up(f[x],size[y]); 74 } 75 } 76 up(f[x],sum-size[x]); 77 if(f[rt]>f[x])rt=x; 78 } 79 void got(int x,int fa,int dep,int color,int sum){ 80 for(int y,i=h[x];i<h[x+1];++i){ 81 y=e[i].to; 82 if(y!=fa && !b[y]){ 83 if(e[i].color==color)w[++ll]=(data){dep+1,sum}; 84 else w[++ll]=(data){dep+1,sum+c[e[i].color]}; 85 got(e[i].to,x,dep+1,e[i].color,w[ll].sum); 86 } 87 } 88 } 89 void solve(int x){ 90 b[x]=1; 91 int i,rt1=0,rt2=cnt=0,j; 92 for(i=h[x];i<h[x+1];++i){ 93 if(i>h[x] && e[i].color>e[i-1].color)rt1=merge(rt1,rt2),rt2=0; 94 if(!b[e[i].to]){ 95 w[ll=1]=(data){1,c[e[i].color]}; 96 got(e[i].to,x,1,e[i].color,c[e[i].color]); 97 ss[i]=ll; 98 for(j=1;j<=ll;++j)if(w[j].dep<=r){ 99 if(w[j].dep>=l)up(ans,w[j].sum); 100 if(w[j].dep<r){ 101 up(ans,query(rt1,1,n,max(1,l-w[j].dep),r-w[j].dep)+w[j].sum); 102 up(ans,query(rt2,1,n,max(1,l-w[j].dep),r-w[j].dep)-c[e[i].color]+w[j].sum); 103 } 104 } 105 for(j=1;j<=ll;++j)if(w[j].dep<=r)add(rt2,1,n,w[j].dep,w[j].sum); 106 } 107 } 108 for(i=h[x];i<h[x+1];++i) 109 if(!b[e[i].to]){ 110 sum=ss[i]; 111 rt=0; 112 dfs(e[i].to,x); 113 solve(rt); 114 } 115 } 116 }t; 117 bool cmp(const edge&a,const edge&b){ 118 return a.from==b.from?a.color<b.color:a.from<b.from; 119 } 120 int main(){ 121 //freopen("input","r",stdin); 122 a[0].v=-inf; 123 t.n=n=getint(); 124 m=getint(); 125 l=getint(); 126 r=getint(); 127 for(i=1;i<=m;++i)c[i]=getint(); 128 for(i=1;i<n;++i){ 129 x=getint(); 130 y=getint(); 131 z=getint(); 132 t.addedge(x,y,z); 133 } 134 std::sort(e+1,e+((n-1)*2)+1,cmp); 135 for(i=1;i<=((n-1)<<1);++i) 136 if(!t.h[e[i].from])t.h[e[i].from]=i; 137 t.h[n+1]=(n-1)<<1|1; 138 t.f[t.rt=0]=inf; 139 t.sum=n; 140 ans=-inf; 141 t.dfs(1,0); 142 t.solve(t.rt); 143 printf("%d\n",ans); 144 }
Review
一開始覺得是樹形dp 後來發現那是錯的
還能夠用單調隊列過 好像更簡單