• CF757G Can Bash Save the Day?


    https://www.luogu.com.cn/problem/CF757G

    可持久化点分树

    首先一个暴力的想法就是点分树上每个点开一个线段树,下标是那个排列 \(p\) 的下标,维护个数和距离和
    但发现这样空间就变成 \(O(n\log ^2 n)\) 了,而且有修改,不能像 开店 那个题那样简化成 vector 上二分
    卡空间的话把线段树改成平衡树,常数变大,但感觉 5s 还是可过

    来个不那么暴力的做法
    由于区间询问可以差分,考虑给每个前缀维护一个点分树
    修改的时候,就从点分树的根开始,每次把上一个前缀这个位置的节点复制过来,把个数、距离和修改掉,儿子们等信息不变
    同样有点分树常见的那个容斥
    然而发现每个点最多会有 \(O(n)\) 个儿子,这样一复制就爆炸了,所以先给原树转化为二叉树,再给这个二叉树建点分树
    这样建完点分树上一个点最多会有 \(3\) 个儿子
    于是时空都是 \(O(n\log n)\)

    转二叉树的过程见代码

    #define N 400006
    #define M 800006
    #define LOG_N 20
    int lg2[N*2];
    struct GraphT{
    	int fir[N],nex[M],to[M],w[M],tot;
    	inline void add(int u,int v,int c,int flag=1){
    		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;w[tot]=c;
    		if(flag) add(v,u,c,0);
    	}
    	inline void clear(){std::memset(fir,0,sizeof fir);tot=0;}
    	int st[LOG_N+2][N*2],id[N*2];
    	int deep[N],dfscnt,dfn[N];
    	long long sum[N];
    	void dfs(int u,int fa=0){
    		deep[u]=deep[fa]+1;dfn[u]=++dfscnt;id[dfscnt]=u;
    		for(int v,i=fir[u];i;i=nex[i]){
    			v=to[i];
    			if(v==fa) continue;
    			sum[v]=sum[u]+w[i];
    			dfs(v,u);id[++dfscnt]=u;
    		}
    	}
    	inline void initLca(){
    		dfs(1);st[0][1]=id[1];
    		for(int i=2;i<=dfscnt;i++) lg2[i]=lg2[i>>1]+1,st[0][i]=id[i];
    		for(int j=1;j<=LOG_N;j++)for(int i=1;i+(1<<j)<=dfscnt;i++) st[j][i]=deep[st[j-1][i]]<deep[st[j-1][i+(1<<(j-1))]]?st[j-1][i]:st[j-1][i+(1<<(j-1))];
    	}
    	inline int getLca(int u,int v)const{
    		if(dfn[u]>dfn[v]) lib::swap(u,v);
    		u=dfn[u];v=dfn[v];
    		int o=lg2[v-u+1];
    		return deep[st[o][u]]<deep[st[o][v-(1<<o)+1]]?st[o][u]:st[o][v-(1<<o)+1];
    	}
    	inline long long getDis(const int &u,const int &v)const{return sum[u]+sum[v]-(sum[getLca(u,v)]<<1);}
    }G,T;//T rebuild -> G
    int n;
    int root,size[N],maxson[N],vis[N];
    void findRoot(int u,int fa=0){
    	size[u]=1;maxson[u]=0;
    	for(int v,i=G.fir[u];i;i=G.nex[i]){
    		v=G.to[i];
    		if(v==fa||vis[v]) continue;
    		findRoot(v,u);size[u]+=size[v];
    		lib::chkMax(maxson[u],size[v]);
    	}
    	lib::chkMax(maxson[u],size[0]-size[u]);
    	if(maxson[u]<maxson[root]) root=u;
    }
    struct Node{
    	Node *son[3];
    	int id,size;
    	long long sum,sumfa;
    }addr[N*30],*totAddr=addr,*rt[N];//rt: root
    int newFa[N],deep[N];
    std::vector<int>sonId[N];
    inline void New(Node *&x){x=totAddr++;}
    void divide(int u,Node *now,int tot){
    	vis[u]=1;now->id=u;
    	Node *nex;
    	for(int v,i=G.fir[u];i;i=G.nex[i]){
    		v=G.to[i];
    		if(vis[v]) continue;
    		root=0;size[0]=size[v]>size[u]?(tot-size[u]):size[v];
    		findRoot(v);newFa[root]=u;deep[root]=deep[u]+1;	
    		for(int j=0;j<deep[u];j++) sonId[root].push_back(sonId[u][j]);
    		New(nex);
    		if(!now->son[0]) now->son[0]=nex,sonId[root].push_back(0);
    		else if(!now->son[1]) now->son[1]=nex,sonId[root].push_back(1);
    		else now->son[2]=nex,sonId[root].push_back(2);
    		divide(root,nex,size[v]);
    	}
    }
    int deg[N],totNode;
    void rebuild(int u,int fa=0){
    	for(int last=0,tmp=0,v,i=T.fir[u];i;i=T.nex[i]){
    		v=T.to[i];
    		if(v==fa) continue;
    		if(++tmp==1) G.add(u,v,T.w[i]),last=u;
    		else if(tmp==deg[u]-(u!=1)) G.add(last,v,T.w[i]);
    		else G.add(last,++totNode,0),G.add(totNode,v,T.w[i]),last=totNode;
    	}
    	for(int i=T.fir[u];i;i=T.nex[i])if(T.to[i]^fa) rebuild(T.to[i],u);
    }
    inline void build(){
    	totNode=n;rebuild(1);
    	root=0;maxson[0]=_INT_INF;size[0]=n;
    	findRoot(1);
    	New(rt[0]);divide(root,rt[0],size[1]);
    }
    inline void update(Node *last,Node *&tree,int u,int k){
    	New(tree);
    	Node *now=tree;
    	for(int id=0;;){
    		*now=*last;id=now->id;
    		now->size+=k;now->sum+=k*G.getDis(u,id);
    		if(newFa[id]) now->sumfa+=k*G.getDis(u,newFa[id]);
    		if(id==u) return;
    		last=last->son[sonId[u][deep[id]]];
    		New(now->son[sonId[u][deep[id]]]);now=now->son[sonId[u][deep[id]]];
    	}
    }
    inline long long ask(Node *l,Node *r,int u){
    	long long ans=0;
    	Node *nexL,*nexR;
    	for(int i=0;i<deep[u];i++,l=nexL,r=nexR){
    		nexL=l->son[sonId[u][i]];nexR=r->son[sonId[u][i]];
    		ans+=(r->size-nexR->size-(l->size-nexL->size))*G.getDis(u,r->id)+(r->sum-nexR->sumfa-(l->sum-nexL->sumfa));
    	}
    	return ans+r->sum-l->sum;
    }
    int main(){
    	n=read();int q=read();
    	static int p[N];
    	for(int i=1;i<=n;i++) p[i]=read();
    	for(int u,v,i=1;i<n;i++) u=read(),v=read(),T.add(u,v,read()),deg[u]++,deg[v]++;
    	build();
    	G.initLca();
    	for(int i=1;i<=n;i++) update(rt[i-1],rt[i],p[i],1);
    	long long lastans=0;
    	#define MOD 1073741824
    	while(q--){
    		int op=read();
    		if(op==1){
    			int l=read()^lastans,r=read()^lastans;
    			writeEN(lastans=ask(rt[l-1],rt[r],read()^lastans));lastans%=MOD;
    		}
    		else{
    			int u=read()^lastans;
    			lib::swap(p[u],p[u+1]);update(rt[u-1],rt[u],p[u],1);
    		}
    	}
    	return RET;
    }
    
  • 相关阅读:
    oracle安装异常汇总
    使用口令文件认证
    oracle的网络连接
    只有数据文件恢复数据库
    ORACLE-SQLLOAD导入外部数据详解
    主,备数据库--静态监听配置
    使用RMAN Active duplicate创建异地auxiliary Database
    maven仓库之第一篇
    Oracle数据库之第四篇
    Oracle数据库之第三篇
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/15964239.html
Copyright © 2020-2023  润新知