解题:洛谷4556 雨天的尾巴

题面

第一次写线段树合并

因为最后只有一次询问,所以树上差分,动态开点权值线段树维护,主要说线段树合并的部分

 1 int merge(int x,int y,int l,int r)
 2 {
 3     if(!x||!y) return x|y;
 4     int tmp=x,mid=(l+r)/2;
 5     val[tmp]=val[x]+val[y];
 6     son[tmp][0]=merge(son[x][0],son[y][0],l,mid);
 7     son[tmp][1]=merge(son[x][1],son[y][1],mid+1,r);
 8     if(l==r) maxx[tmp]=val[tmp],pos[tmp]=l; else pushup(tmp);
 9     return tmp;
10 }

(Zhang_RQ式线段树合并)

1.有一个节点为空则返回另一个

2.合并信息

3.分别用两个节点的左右儿子和左右区间合并出新节点的左右儿子

4.pushup

注意只有当一个点的最大值不为零时才将答案更新,否则输出零

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=100005;
  6 int son[4*18*N][2],val[4*18*N],maxx[4*18*N],pos[4*18*N];
  7 int num[N],dep[N],anc[N],siz[N],imp[N],top[N],outp[N];
  8 int p[N],noww[2*N],goal[2*N];
  9 int n,m,t1,t2,t3,cnt,tot,c;
 10 void link(int f,int t)
 11 {
 12     noww[++cnt]=p[f];
 13     goal[cnt]=t,p[f]=cnt;
 14 }
 15 void DFS(int nde,int fth,int dth)
 16 {
 17     int tmp=0;
 18     siz[nde]=1,anc[nde]=fth,dep[nde]=dth;
 19     for(int i=p[nde];i;i=noww[i])
 20         if(goal[i]!=fth)
 21         {
 22             DFS(goal[i],nde,dth+1);
 23             siz[nde]+=siz[goal[i]];
 24             if(siz[goal[i]]>tmp)
 25                 tmp=siz[goal[i]],imp[nde]=goal[i];
 26         }
 27 }
 28 void MARK(int nde,int tpp)
 29 {
 30     top[nde]=tpp;
 31     if(imp[nde])
 32     {
 33         MARK(imp[nde],tpp);
 34         for(int i=p[nde];i;i=noww[i])
 35             if(goal[i]!=anc[nde]&&goal[i]!=imp[nde])
 36                 MARK(goal[i],goal[i]);
 37     }
 38 }
 39 int LCA(int x,int y)
 40 {
 41     int tx=top[x],ty=top[y];
 42     while(tx!=ty)
 43     {
 44         if(dep[tx]<dep[ty])
 45             swap(tx,ty),swap(x,y);
 46         x=anc[tx],tx=top[x];
 47     }
 48     return dep[x]<dep[y]?x:y;
 49 }
 50 void pushup(int nde)
 51 {
 52     int ls=son[nde][0],rs=son[nde][1];
 53     maxx[nde]=max(maxx[ls],maxx[rs]);
 54     pos[nde]=(maxx[nde]==maxx[ls])?pos[ls]:pos[rs];
 55 }
 56 void create(int &nde,int l,int r,int p,int task)
 57 {
 58     if(!nde) nde=++c; val[nde]+=task;
 59     if(l==r) pos[nde]=l,maxx[nde]=val[nde];
 60     else
 61     {
 62         int mid=(l+r)/2;
 63         if(p<=mid) create(son[nde][0],l,mid,p,task);
 64         else create(son[nde][1],mid+1,r,p,task); pushup(nde);
 65     }
 66 }
 67 int merge(int x,int y,int l,int r)
 68 {
 69     if(!x||!y) return x|y;
 70     int tmp=x,mid=(l+r)/2;
 71     val[tmp]=val[x]+val[y];
 72     son[tmp][0]=merge(son[x][0],son[y][0],l,mid);
 73     son[tmp][1]=merge(son[x][1],son[y][1],mid+1,r);
 74     if(l==r) maxx[tmp]=val[tmp],pos[tmp]=l; else pushup(tmp);
 75     return tmp;
 76 }
 77 void ANS(int nde)
 78 {
 79     for(int i=p[nde];i;i=noww[i])
 80         if(goal[i]!=anc[nde])
 81             ANS(goal[i]),num[nde]=merge(num[nde],num[goal[i]],1,100000);
 82     outp[nde]=maxx[num[nde]]?pos[num[nde]]:0;
 83 }
 84 int main ()
 85 {
 86     scanf("%d%d",&n,&m);
 87     for(int i=1;i<n;i++)
 88     {
 89         scanf("%d%d",&t1,&t2);
 90         link(t1,t2),link(t2,t1);
 91     }
 92     DFS(1,0,1); MARK(1,1);
 93     for(int i=1;i<=m;i++)
 94     {
 95         scanf("%d%d%d",&t1,&t2,&t3);
 96         int lca=LCA(t1,t2);
 97         create(num[t1],1,100000,t3,1);
 98         create(num[t2],1,100000,t3,1);
 99         create(num[lca],1,100000,t3,-1);
100         create(num[anc[lca]],1,100000,t3,-1);
101     }
102     ANS(1);
103     for(int i=1;i<=n;i++)
104         printf("%d\n",outp[i]);
105     return 0;    
106 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/9672538.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值