ToB企服应用市场:ToB评测及商务社交产业平台
标题:
动态开点线段树
[打印本页]
作者:
数据人与超自然意识
时间:
2024-7-28 12:30
标题:
动态开点线段树
标题链接
思路
对于树的线路题目可以用树剖来分别成一段一段的一连区间,但由于只记录这些区间某个信仰的权值,而且只有单点修改,所以我们思量给每个信仰都开一个线段树,也就是开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企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4