zoukankan      html  css  js  c++  java
  • loj558&loj2011

    loj 2011

    题意:一棵树 有两种操作 1.选定一个点 且这个点的权值随着时间的增加而增加1

                 2.查询一条路径上点的个数和权值大于C的个数

    题解:刚开始没想到离线的做法 认为可以大力线段树 n(logn)^3 然而显然过不去 被韦神教育后也考虑过树上莫队的写法 然而n^(5/3)然并卵 偷偷瞄了一眼题解

    发现我们可以这样离线一下 然后少掉一个log 对于每个querty我们找到临界位置max(0,i-C-1) 这样的话 我们只要去找当临界位置的时候在这条链上的被更新的点的个数 这样的话 我们树状数组维护就ojbk了

    #include <bits/stdc++.h>
    #define ll long long
    #define s second
    #define f first
    #define pii pair<int,int>
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=2e5+10;
    using namespace std;
    vector<int>vec[MAXN];
    int son[MAXN],fa[MAXN],num[MAXN],dep[MAXN];
    int n,q;
    void dfs1(int v,int pre,int deep){
    	num[v]=1;dep[v]=deep+1;fa[v]=pre;
    	for(int i=0;i<vec[v].size();i++){
    		int u=vec[v][i];
    		if(u!=pre){
    			dfs1(u,v,deep+1);
    			num[v]+=num[u];
    			if(son[v]==-1||num[son[v]]<num[u]) son[v]=u;
    		}
    	}
    }
    int tp[MAXN],p[MAXN],fp[MAXN],cnt;
    void dfs2(int v,int td){
    	p[v]=++cnt;fp[cnt]=v;tp[v]=td;
    	if(son[v]!=-1) dfs2(son[v],td);
    	for(int i=0;i<vec[v].size();i++){
    		int u=vec[v][i];
    		if(u!=fa[v]&&u!=son[v]) dfs2(u,u);
    	}
    }
    int d[MAXN];
    int get_id(int x){
    	return x&(-x);
    }
    void add(int x){
    	for(int i=x;i<=n;i+=get_id(i)) d[i]++;
    }
    int querty(int x){
    	int ans=0;
    	for(int i=x;i>0;i-=get_id(i)) ans+=d[i];
    	return ans;
    }
    typedef struct node{
    	int u,v,id,p;
    	friend bool operator<(node aa,node bb){
    		return aa.p<bb.p;
    	}
    }node;
    int get1(int u,int v){
    	int uu=tp[u];int vv=tp[v];
    	int ans=0;
    	while(uu!=vv){
    		if(dep[uu]<dep[vv]) swap(uu,vv),swap(u,v);
    		ans+=(p[u]-p[uu]+1);
    		u=fa[uu];uu=tp[u];
    	}
    	if(dep[u]>dep[v]) swap(u,v);
    	ans+=(p[v]-p[u]+1);
    	return ans;
    }
    int get2(int u,int v){
    	int uu=tp[u];int vv=tp[v];
    	int ans=0;
    	while(uu!=vv){
    		if(dep[uu]<dep[vv]) swap(uu,vv),swap(u,v);
    		ans+=(querty(p[u])-querty(p[uu]-1));
    		u=fa[uu];uu=tp[u];
    	}
    	if(dep[u]>dep[v]) swap(u,v);
    	ans+=(querty(p[v])-querty(p[u]-1));
    	return ans;
    }
    node que[MAXN];
    bool pd[MAXN];
    pii ans1[MAXN];
    int vis[MAXN];
    int main(){
    	scanf("%d",&n);int rt;
    	int t;
    	for(int i=1;i<=n;i++){
    		scanf("%d",&t);son[i]=-1;
    		if(t==0){
    			rt=i;continue;
    		}
    		vec[i].push_back(t);
    		vec[t].push_back(i);
    	}cnt=0;
    	int cnt1=0;
    	dfs1(rt,0,0);dfs2(rt,rt);
    	scanf("%d",&q);
    	int op,u,v,c;
    	for(int i=1;i<=q;i++){
    		scanf("%d",&op);
    		if(op==1){
    			scanf("%d%d%d",&u,&v,&c);
    			ans1[i].f=get1(u,v);
    			que[++cnt1].u=u;que[cnt1].v=v;que[cnt1].p=max(0,i-c-1);que[cnt1].id=i;
    		}
    		else{
    			scanf("%d",&u);
    			if(pd[u]) continue;
    			vis[i]=u;pd[u]=1;
    		}
    	}
    	sort(que+1,que+cnt1+1);
    	int _=1;
    	for(int i=0;i<=q;i++){
    		if(vis[i]) add(p[vis[i]]);
    		for(;_<=cnt1&&que[_].p==i;_++){
    			ans1[que[_].id].s=get2(que[_].u,que[_].v);
    		}
    	}
    //	if(_<=cnt1){
    //		for(;_<=cnt1;_++){
    //			ans1[que[_].id].s=get2(que[_].u,que[_].v);
    //		}
    //	}
    	for(int i=1;i<=q;i++)if(!vis[i]) printf("%d %d
    ",ans1[i].f,ans1[i].s);
    	return 0;
    }
    

     loj 558

     题意:有一个森林 初始时刻每个点都是白色的  现在有四种操作

        1.对于u颜色反转

        2.连接u,v

        3.断开u,v

        4.查询与u联通的所有黑点到u的距离的和

    题解:大概很巧妙的是LCT维护子树信息 然后维护LCT维护当前节点的这段链上的贡献 注意反转的时候交换就行了 (但是这个题很毒 指针版本的LCT会A掉 然而数组版本的会T 虽然数组版本的没有A掉 就当作练习了

    #include <cctype>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define pii pair<int,int>
    #define il inline
    #define f first
    #define s second
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,l,r) for(int i=l;i>=r;i--)
    #define ll long long
    #define rg register
    const int MAXN=5e5+10;
    using namespace std;
    il int read() {
    	rg int x=0,f=1;
    	rg char ch=getchar();
    	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    int ch[MAXN][2],cnt,res[MAXN],pre[MAXN],st[MAXN],tp;
    ll sum[MAXN],chsum[MAXN],ke[MAXN],rsum[MAXN],num[MAXN],chnum[MAXN],vul[MAXN],size[MAXN];
    bool rt[MAXN],key[MAXN];
    il void reverse(int r) {
    	if(!r) return ;
    	std::swap(ch[r][0],ch[r][1]);
    	std::swap(sum[r],rsum[r]);
    	res[r]^=1;
    }
    il void push(int x) {
    	if(res[x]) {
    		reverse(ch[x][0]);
    		reverse(ch[x][1]);
    		res[x]=0;
    	}
    }
    il void up(int x) {
    	if(!x) return ;
    	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    	num[x]=num[ch[x][0]]+num[ch[x][1]]+chnum[x]+key[x];
    	vul[x]=vul[ch[x][0]]+vul[ch[x][1]]+ke[x];
    	rsum[x]=rsum[ch[x][0]]+rsum[ch[x][1]]+chsum[x]+1ll*(vul[ch[x][1]]+ke[x])*(num[ch[x][0]]+chnum[x]+key[x]);
    	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+chsum[x]+1ll*(vul[ch[x][0]]+ke[x])*(num[ch[x][1]]+chnum[x]+key[x]);
    }
    il void P(int x) {
    	rg int i;
    	st[++tp]=x;
    	for(i=x; !rt[i]; i=pre[i]) st[++tp]=pre[i];
    	for(; tp; tp--) push(st[tp]);
    }
    il void rotate(int x,int kind) {
    	rg int y=pre[x];
    	ch[y][!kind]=ch[x][kind];
    	pre[ch[x][kind]]=y;
    	if(rt[y]) rt[x]=1,rt[y]=0;
    	else ch[pre[y]][ch[pre[y]][1]==y]=x;
    	pre[x]=pre[y];
    	ch[x][kind]=y;
    	pre[y]=x;
    	up(y);
    }
    il void splay(int x) {
    	P(x);
    	while(!rt[x]) {
    		if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
    		else {
    			rg int y=pre[x];
    			rg int kind=ch[pre[y]][0]==y;
    			if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
    			else rotate(y,kind),rotate(x,kind);
    		}
    	}
    	up(x);
    }
    il void access(int x) {
    	rg int y=0;
    	while(x) {
    		splay(x);
    		if(ch[x][1]) {
    			rt[ch[x][1]]=1;
    			pre[ch[x][1]]=x;
    			chsum[x]+=sum[ch[x][1]];
    			chnum[x]+=num[ch[x][1]];
    		}
    		if(y) rt[y]=0,chsum[x]-=sum[y],chnum[x]-=num[y];
    		ch[x][1]=y;
    		up(x);
    		y=x;
    		x=pre[x];
    	}
    }
    il void mroot(int u) {
    	access(u);
    	splay(u);
    	reverse(u);
    }
    il void Link(int u,int v) {
    	mroot(u);
    	mroot(v);
    	pre[u]=v;
    	chnum[v]+=num[u];
    	chsum[v]+=sum[u];
    	up(v);
    }
    il void destory(int u,int v) {
    	//if(!pd(u,v)) return ;
    	mroot(u);
    	access(v);
    	splay(u);
    	pre[v]=0;rt[v]=1;
    	ch[u][1]=0;up(u);
    	//up(x);
    }
    int main() {
    	//freopen("1.in","r",stdin);
    	//freopen("2.out","w",stdout);
    	int n,m,k;
    	n=read();
    	m=read();
    	k=read();
    	cnt=0;
    	tp=0;
    	inc(i,1,n) size[++cnt]=1,rt[cnt]=1;
    	int u,v,w;
    	while(m--) {
    		u=read();
    		v=read();
    		w=read();
    		size[++cnt]=1,rt[cnt]=1;
    		ke[cnt]=vul[cnt]=w;
    		Link(u,cnt);
    		Link(v,cnt);
    	}
    	char str[5];
    	while(k--) {
    		scanf("%s",str);
    		if(str[0]=='L') {
    			u=read(),v=read(),w=read(),size[++cnt]=1,rt[cnt]=1;
    			ke[cnt]=vul[cnt]=w;
    			Link(u,cnt),Link(v,cnt);
    		} else if(str[0]=='C') {
    			u=read();
    			v=read();
    			destory(u,v);
    		} else if(str[0]=='F') u=read(),mroot(u),key[u]^=1,up(u);
    		else u=read(),mroot(u),printf("%lld
    ",sum[u]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    出现“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的解决方法
    angular中的:class的使用
    Vue中的:class的使用
    audio 音乐自动播放,循环播放,隐藏等
    vue放大缩小视图窗口按钮
    js获取显示器、页面等高度 (转)
    在 vue 中添加错误与成功提示的代码段
    在 vue 中添加初始化代码段
    学习react基本语法初始化webpack.pub.config.js
    学习react基本语法初始化webpack.config.js
  • 原文地址:https://www.cnblogs.com/wang9897/p/8973551.html
Copyright © 2011-2022 走看看