标题链接
思路
对于树的线路题目可以用树剖来分别成一段一段的一连区间,但由于只记录这些区间某个信仰的权值,而且只有单点修改,所以我们思量给每个信仰都开一个线段树,也就是开1e5个线段树(类似主席树的写法,开个root数组来记录每个线段树的根,然后布局体来存那些点和他们的信息,左右儿子),用每个线段树来维护各个信仰的区间和与区间最大值。
- #include<bits/stdc++.h>
- using namespace std;
- #define int long long
- typedef long long ll;
- typedef pair<int,int> pii;
- const int inf=0x3f3f3f3f;
- const int N=1e5+10;
- const int mod=1e9+7;
- #define fi first
- #define se second
- int n,q;
- int w[N],c[N];
- vector<int> e[N];
- //树剖
- int siz[N],dep[N],newid[N],newc[N],neww[N];
- int treecut,son[N],fa[N],top[N];
- void dfs(int x,int f){
- siz[x]=1;
- fa[x]=f;
- dep[x]=dep[f]+1;
- for(auto y:e[x]){
- if(y==f)
- continue;
- dfs(y,x);
- siz[x]+=siz[y];
- if(siz[y]>siz[son[x]])
- son[x]=y;
- }
- }
- void dfs(int x,int f,int id){
- newid[x]=++treecut;
- top[x]=id;//是用原节点x来记录top,因为top是在树在lca的,树上的信息都记录的x,treecut已经转化成链了
- newc[treecut]=c[x];//这些都是维护新下标的信息
- neww[treecut]=w[x];
- if(son[x]){
- dfs(son[x],x,id);//仍然是id,表示这条重链的头都是id
- }
- for(auto y:e[x]){
- if(y==f||y==son[x]) //重儿子不要再进
- continue;
- dfs(y,x,y);
- }
- }
- //线段树
- int root[N],treecnt;
- struct node{
- int l,r,maxx,sum;
- }tree[N*20];
- void pushup(int l,int r,int &k){
- int ls=tree[k].l,rs=tree[k].r;
- tree[k].maxx=max(tree[ls].maxx,tree[rs].maxx);
- tree[k].sum=tree[ls].sum+tree[rs].sum;
- }
- void modify(int l,int r,int &k,int x,int value){
- if(!k) k=++treecnt;//k是引用,为0表示为NULL,要创节点
- if(l==r){
- tree[k].maxx=tree[k].sum=value;
- return;
- }
- int mid=(l+r)>>1;
- if(x<=mid) modify(l,mid,tree[k].l,x,value);
- else modify(mid+1,r,tree[k].r,x,value);
- pushup(l,r,k);
- }
- int querysum(int l,int r,int &k,int x,int y){
- if(x<=l&&y>=r)
- return tree[k].sum;
- int mid=(l+r)>>1;
- int res=0;
- if(x<=mid) res+=querysum(l,mid,tree[k].l,x,y);
- if(y>mid) res+=querysum(mid+1,r,tree[k].r,x,y);
- return res;
- }
- int querymax(int l,int r,int &k,int x,int y){
- if(x<=l&&y>=r)
- return tree[k].maxx;
- int mid=(l+r)>>1;
- int res=0;
- if(x<=mid) res=max(res,querymax(l,mid,tree[k].l,x,y));
- if(y>mid) res=max(res,querymax(mid+1,r,tree[k].r,x,y));
- return res;
- }
- //lca
- int cc;//表示lca的子树是哪个信仰子树
- int lcasum(int a,int b){
- int res=0;
- while(top[a]!=top[b]){//不在同一重链
- if(dep[top[a]]<dep[top[b]])//保证a所在链的dep要大
- swap(a,b);
- res+=querysum(1,n,root[cc],newid[top[a]],newid[a]);
- a=fa[top[a]];//要fa来跳出这条链
- }
- if(newid[a]>newid[b])
- swap(a,b);
- res+=querysum(1,n,root[cc],newid[a],newid[b]);
- return res;
- }
- int lcamax(int a,int b){
- int res=0;
- while(top[a]!=top[b]){
- if(dep[top[a]]<dep[top[b]])
- swap(a,b);
- res=max(res,querymax(1,n,root[cc],newid[top[a]],newid[a]));
- a=fa[top[a]];
- }
- if(newid[a]>newid[b])
- swap(a,b);
- res=max(res,querymax(1,n,root[cc],newid[a],newid[b]));
- return res;
- }
- void solve(){
- cin>>n>>q;
- for(int i=1;i<=n;i++){
- cin>>w[i]>>c[i];
- }
- for(int i=1;i<n;i++){
- int a,b;cin>>a>>b;
- e[a].push_back(b);
- e[b].push_back(a);
- }
-
- dfs(1,0);
- dfs(1,0,1);
- for(int i=1;i<=n;i++){//全用新的了...
- modify(1,n,root[newc[newid[i]]],newid[i],neww[newid[i]]);
- }
- while(q--){
- string s;
- cin>>s;
- int x,y;
- cin>>x>>y;
- cc=newc[newid[x]];//信仰
- if(s=="CC"){
- int t=querysum(1,n,root[newc[newid[x]]],newid[x],newid[x]);
- modify(1,n,root[newc[newid[x]]],newid[x],0);
- modify(1,n,root[y],newid[x],t);
- newc[newid[x]]=y;//记得修改信仰
- }
- else if(s=="CW"){
- modify(1,n,root[newc[newid[x]]],newid[x],y);
- neww[newid[x]]=y;
- }
- else if(s=="QS"){
- cout<<lcasum(x,y)<<endl;
- }
- else{
- cout<<lcamax(x,y)<<endl;
- }
- }
- }
- signed main(){
- ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
- int t=1;
- //cin>>t;
- while(t--){
- solve();
- }
- return 0;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |