动态开点线段树

打印 上一主题 下一主题

主题 681|帖子 681|积分 2043

标题链接
思路
        对于树的线路题目可以用树剖来分别成一段一段的一连区间,但由于只记录这些区间某个信仰的权值,而且只有单点修改,所以我们思量给每个信仰都开一个线段树,也就是开1e5个线段树(类似主席树的写法,开个root数组来记录每个线段树的根,然后布局体来存那些点和他们的信息,左右儿子),用每个线段树来维护各个信仰的区间和与区间最大值。
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. typedef long long ll;
  5. typedef pair<int,int> pii;
  6. const int inf=0x3f3f3f3f;
  7. const int N=1e5+10;
  8. const int mod=1e9+7;
  9. #define fi first
  10. #define se second
  11. int n,q;
  12. int w[N],c[N];
  13. vector<int> e[N];
  14. //树剖
  15. int siz[N],dep[N],newid[N],newc[N],neww[N];
  16. int treecut,son[N],fa[N],top[N];
  17. void dfs(int x,int f){
  18.         siz[x]=1;
  19.         fa[x]=f;
  20.         dep[x]=dep[f]+1;
  21.         for(auto y:e[x]){
  22.                 if(y==f)
  23.                         continue;
  24.                 dfs(y,x);
  25.                 siz[x]+=siz[y];
  26.                 if(siz[y]>siz[son[x]])
  27.                         son[x]=y;
  28.         }
  29. }
  30. void dfs(int x,int f,int id){
  31.         newid[x]=++treecut;
  32.         top[x]=id;//是用原节点x来记录top,因为top是在树在lca的,树上的信息都记录的x,treecut已经转化成链了
  33.         newc[treecut]=c[x];//这些都是维护新下标的信息
  34.         neww[treecut]=w[x];
  35.         if(son[x]){
  36.                 dfs(son[x],x,id);//仍然是id,表示这条重链的头都是id
  37.         }
  38.         for(auto y:e[x]){
  39.                 if(y==f||y==son[x]) //重儿子不要再进
  40.                         continue;
  41.                 dfs(y,x,y);
  42.         }
  43. }
  44. //线段树
  45. int root[N],treecnt;
  46. struct node{
  47.         int l,r,maxx,sum;
  48. }tree[N*20];
  49. void pushup(int l,int r,int &k){
  50.         int ls=tree[k].l,rs=tree[k].r;
  51.         tree[k].maxx=max(tree[ls].maxx,tree[rs].maxx);
  52.         tree[k].sum=tree[ls].sum+tree[rs].sum;
  53. }
  54. void modify(int l,int r,int &k,int x,int value){
  55.         if(!k) k=++treecnt;//k是引用,为0表示为NULL,要创节点
  56.         if(l==r){
  57.                 tree[k].maxx=tree[k].sum=value;
  58.                 return;
  59.         }
  60.         int mid=(l+r)>>1;
  61.         if(x<=mid) modify(l,mid,tree[k].l,x,value);
  62.         else modify(mid+1,r,tree[k].r,x,value);
  63.         pushup(l,r,k);
  64. }
  65. int querysum(int l,int r,int &k,int x,int y){
  66.         if(x<=l&&y>=r)
  67.                 return tree[k].sum;
  68.         int mid=(l+r)>>1;
  69.         int res=0;
  70.         if(x<=mid) res+=querysum(l,mid,tree[k].l,x,y);
  71.         if(y>mid) res+=querysum(mid+1,r,tree[k].r,x,y);
  72.         return res;
  73. }
  74. int querymax(int l,int r,int &k,int x,int y){
  75.         if(x<=l&&y>=r)
  76.                 return tree[k].maxx;
  77.         int mid=(l+r)>>1;
  78.         int res=0;
  79.         if(x<=mid) res=max(res,querymax(l,mid,tree[k].l,x,y));
  80.         if(y>mid) res=max(res,querymax(mid+1,r,tree[k].r,x,y));
  81.         return res;
  82. }
  83. //lca
  84. int cc;//表示lca的子树是哪个信仰子树
  85. int lcasum(int a,int b){
  86.         int res=0;
  87.         while(top[a]!=top[b]){//不在同一重链
  88.                 if(dep[top[a]]<dep[top[b]])//保证a所在链的dep要大
  89.                         swap(a,b);
  90.                 res+=querysum(1,n,root[cc],newid[top[a]],newid[a]);
  91.                 a=fa[top[a]];//要fa来跳出这条链
  92.         }
  93.         if(newid[a]>newid[b])
  94.                 swap(a,b);
  95.         res+=querysum(1,n,root[cc],newid[a],newid[b]);
  96.         return res;
  97. }
  98. int lcamax(int a,int b){
  99.         int res=0;
  100.         while(top[a]!=top[b]){
  101.                 if(dep[top[a]]<dep[top[b]])
  102.                         swap(a,b);
  103.                 res=max(res,querymax(1,n,root[cc],newid[top[a]],newid[a]));
  104.                 a=fa[top[a]];
  105.         }
  106.         if(newid[a]>newid[b])
  107.                 swap(a,b);
  108.         res=max(res,querymax(1,n,root[cc],newid[a],newid[b]));
  109.         return res;
  110. }
  111. void solve(){
  112.         cin>>n>>q;
  113.         for(int i=1;i<=n;i++){
  114.                 cin>>w[i]>>c[i];
  115.         }
  116.         for(int i=1;i<n;i++){
  117.                 int a,b;cin>>a>>b;
  118.                 e[a].push_back(b);
  119.                 e[b].push_back(a);
  120.         }
  121.        
  122.         dfs(1,0);
  123.         dfs(1,0,1);
  124.         for(int i=1;i<=n;i++){//全用新的了...
  125.                 modify(1,n,root[newc[newid[i]]],newid[i],neww[newid[i]]);
  126.         }
  127.         while(q--){       
  128.                 string s;
  129.                 cin>>s;
  130.                 int x,y;
  131.                 cin>>x>>y;
  132.                 cc=newc[newid[x]];//信仰
  133.                 if(s=="CC"){
  134.                         int t=querysum(1,n,root[newc[newid[x]]],newid[x],newid[x]);
  135.                         modify(1,n,root[newc[newid[x]]],newid[x],0);
  136.                         modify(1,n,root[y],newid[x],t);
  137.                         newc[newid[x]]=y;//记得修改信仰
  138.                 }
  139.                 else if(s=="CW"){
  140.                         modify(1,n,root[newc[newid[x]]],newid[x],y);
  141.                         neww[newid[x]]=y;
  142.                 }
  143.                 else if(s=="QS"){
  144.                         cout<<lcasum(x,y)<<endl;
  145.                 }
  146.                 else{
  147.                         cout<<lcamax(x,y)<<endl;
  148.                 }
  149.         }
  150. }
  151. signed  main(){
  152.         ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  153.         int t=1;
  154.         //cin>>t;
  155.         while(t--){
  156.                 solve();
  157.         }
  158.         return 0;
  159. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表