【GDOI2017模拟】树的难题
2017-04-22 21:29
302 查看
Description
Solution
比较明显的树分治,把树分治之后直接对其子树进行处理,因为这道题目并不需要去掉子树的重复贡献,比起其他的一些题就要更好处理了。对于一个以重心为根的子树,关键在于如何把每一棵子树都合并起来,可以发现要分成两种情况来计算贡献:当前根到子树的颜色与要合并子树的颜色相同或不同,因为相同就要减去重复的边的贡献,为了方便处理,我们要把子树的颜色排序,然后用树状数组维护。
Code
#include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> #include<iostream> using namespace std; #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) #define rep(i,x) for(i=la[x];i;i=ne[i]) typedef long long ll; const int N=2e5+5,INF=-0x7fffffff/3; struct arr{ int x,se; }son ; int node ,da[N*2],ne[N*2],la ,v ,col[N*2]; int t[3] ,T[3] ,d[3] ,de ,lc ,fa ,D ; ll g ,ans,mx; int n,m,L,R,i,j,x,y,z,l,r,sum,num,tot,hea; bool p ,P[3] ,bz ; bool cmp(arr x,arr y){return x.se<y.se;} void ins(int x,int y,int z){ da[++sum]=y,ne[sum]=la[x],la[x]=sum,col[sum]=z; da[++sum]=x,ne[sum]=la[y],la[y]=sum,col[sum]=z; } void gnode(int x){ int i,l=0,r=1;D[1]=x;fa[x]=0; while(l<r){ x=D[++l]; rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]) D[++r]=da[i],fa[da[i]]=x; }l++; while(l>1){ x=D[--l];node[x]=1; rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]) node[x]+=node[da[i]]; } } void gheav(int x,int size){ int i,l=0,r=1;bz[x]=1;D[1]=x;fa[x]=0; while(l<r){ x=D[++l]; rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]){ if(node[da[i]]>size/2) bz[x]=0; D[++r]=da[i];bz[da[i]]=1;fa[da[i]]=x; } }l++; while(l>1){ x=D[--l];if(bz[x]&&size-node[x]<=size/2) hea=x; } } void sao(int x){ int i,l,r; l=0;r=1;D[1]=x; while(l<r){ x=D[++l]; if(de[x]>R) return; if(de[x]>=L) ans=(ans>g[x])?ans:g[x]; d[2][++d[2][0]]=de[x];P[2][de[x]]=1; t[2][de[x]]=T[2][de[x]]=(t[2][de[x]]>g[x])?t[2][de[x]]:g[x]; rep(i,x) if(da[i]!=fa[x]&&!p[da[i]]){ de[da[i]]=de[x]+1;lc[da[i]]=col[i];g[da[i]]=g[x]; if(lc[x]!=col[i]) g[da[i]]+=v[col[i]]; fa[da[i]]=x;D[++r]=da[i]; } } } void ask(int x,int l,int r){ tot=INF; while(l<=r){ if (r-(r&-r)>=l) tot=(t[x][r]>tot)?t[x][r]:tot,r-=r&-r; else tot=(T[x][r]>tot)?T[x][r]:tot,r--; } } void add(int x,int y,int z,int a){ T[x][y]=(T[x][y]>a)?T[x][y]:a; for(;y<=n;y+=(y&-y)){ if(!P[x][y]) P[x][y]=1,d[x][++d[x][0]]=y; t[x][y]=(t[x][y]>z)?t[x][y]:z; } } void fill(int x){ int i;fo(i,1,d[x][0]) P[x][d[x][i]]=0,t[x][d[x][i]]=T[x][d[x][i]]=INF; d[x][0]=0; } void merge(int x,int y){ int i; fo(i,1,d[y][0]){ add(x,d[y][i],t[y][d[y][i]],T[y][d[y][i]]); P[y][d[y][i]]=0,t[y][d[y][i]]=T[y][d[y][i]]=INF; }d[y][0]=0; } void divi(int x){ int i,j;bool bz; gnode(x);hea=0;gheav(x,node[x]);x=hea; if(ans>mx*node[x]) return; p[x]=true;num=0; rep(i,x) if(!p[da[i]]) son[++num].x=da[i],son[num].se=col[i]; sort(son+1,son+num+1,cmp); fo(i,1,num){ bz=(i-1)?1:0; if(i!=1&&son[i-1].se!=son[i].se) merge(0,1),bz=0; de[son[i].x]=1,lc[son[i].x]=son[i].se,g[son[i].x]=v[son[i].se],fa[son[i].x]=x; sao(son[i].x); fo(j,1,d[2][0]){ l=(L-d[2][j]>1)?L-d[2][j]:1;r=R-d[2][j]; if(bz){ ask(1,l,r); tot+=-v[son[i].se]+t[2][d[2][j]]; ans=(ans>tot)?ans:tot; } ask(0,l,r);tot+=t[2][d[2][j]]; ans=(ans>tot)?ans:tot; } merge(1,2); } fill(0);if(son[num-1].se==son[num].se)fill(1); rep(i,x) if(!p[da[i]]) divi(da[i]); } int main(){ freopen("journey.in","r",stdin); freopen("journey.out","w",stdout); scanf("%d%d%d%d",&n,&m,&L,&R); fo(i,0,2) fo(j,0,n) t[i][j]=T[i][j]=INF; ans=mx=INF; fo(i,1,m) scanf("%d",&v[i]),mx=(mx>v[i])?mx:v[i]; fo(i,1,n-1){ scanf("%d%d%d",&x,&y,&z); ins(x,y,z); } divi(1); printf("%d\n",ans); }
相关文章推荐
- hdu_1251 统计难题 trie模版
- Codevs非难题汇总
- HDU - 1251 统计难题 (字典树)
- FZU - 1686 神龙的难题 重复覆盖
- 洛谷 P1379 八数码难题
- NC:MetaSort通过降低微生物群落复杂度以突破宏基因组组装难题
- 【勤哲应用】勤哲软件解决生产型企业BOM应用难题
- 杭电OJ_(2045)不容易系列之(3)—— LELE的RPG难题
- 【递推问题】LELE的RPG难题
- FZU1686 神龙的难题 —— Dancing Links 可重复覆盖
- java-储物柜难题
- [洛谷10月月赛R1·普及组]T21 SAC E#1 - 一道难题 Tree
- 2017.10.17 蜘蛛难题 思考记录
- HDOJ 2200 Eddy's AC难题
- 重磅 | 机器学习大神Bengio最新论文发布,专注RNN优化难题,将在NIPS提出新概念fraternal dropout
- 小明的难题
- 统计难题
- 大佬的难题
- 学好单片机设计,关于晶振的这些难题一定要先搞懂!
- linux安装难题