zoukankan      html  css  js  c++  java
  • BJOI2014 大融合

    比较好的一个题

    Description

    link

    支持连边和查询一条边两端的连通块的大小乘积的数据结构

    Solution

    原来是用 (LCT) 做的,现在用线段树合并上上

    连接两条边不就是 (merge) 一下

    (merge) 啥就是了个问题

    直接 (dfs) 序上面连续的树的编号就比较可做了

    每次搞是不能整出来 (dfs) 序的,那就离线呗

    先处理出来 (dfs) 序,查询的时候标号就连续了

    权值线段树存标号,所在标号的 (val)(1)

    这题的费时:没有想明白权值线段树存什么(真的是阴沟翻船,并查集 (+) 离线都想出来了)

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	} 
    	const int N=1e5+10,M=5e6+10;
    	struct node{
    		int to,nxt;
    	}e[N<<1];
    	int head[N],cnt,n,T;
    	inline void add(int u,int v)
    	{
    		e[++cnt].to=v; e[cnt].nxt=head[u];
    		return head[u]=cnt,void();
    	}
    	int ls[M],rs[M],val[M],tot;
    	inline void push_up(int x){return val[x]=val[ls[x]]+val[rs[x]],void();}
    	inline void build(int &p,int l,int r,int x)
    	{
    		if(!p) p=++tot; if(l==r) return val[p]++,void();
    		int mid=(l+r)>>1;
    		if(x<=mid) build(ls[p],l,mid,x);
    		else build(rs[p],mid+1,r,x);
    		return push_up(p);
    	}
    	inline int merge(int x,int y,int l,int r)
    	{
    		if(!x||!y) return x+y;
    		int p=++tot,mid=(l+r)>>1;
    		ls[p]=merge(ls[x],ls[y],l,mid);
    		rs[p]=merge(rs[x],rs[y],mid+1,r);
    		return push_up(p),p;
    	}
    	inline int ask(int x,int l,int r,int st,int ed)
    	{
    		if(l<=st&&ed<=r) return val[x];
    		int ans=0,mid=(st+ed)>>1;
    		if(l<=mid) ans+=ask(ls[x],l,r,st,mid);
    		if(r>mid) ans+=ask(rs[x],l,r,mid+1,ed);
    		return ans;
    	}
    	bool vis[N]; int in[N],out[N],tim,id[N],dep[N];
    	inline void dfs(int x,int fa)
    	{
    		in[x]=++tim; vis[x]=1; id[tim]=x; dep[x]=dep[fa]+1;
    		for(int i=head[x];i;i=e[i].nxt)
    		{
    			int t=e[i].to; if(t==fa) continue;
    			dfs(t,x);
    		}out[x]=tim;
    		return ;
    	}
    	string opt[N]; int x[N],y[N],fa[N],rt[N];
    	inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    	signed main()
    	{
    		n=read(); T=read();
    		for(int i=1;i<=n;++i) fa[i]=i;
    		for(int i=1;i<=T;++i) 
    		{
    			cin>>opt[i];
    			x[i]=read(); y[i]=read();
    			if(opt[i][0]=='A') add(x[i],y[i]),add(y[i],x[i]);
    		}
    		int anc=n+1;
    		for(int i=1;i<=n;++i)
    		{
    			if(!in[i]) tim=0,dfs(i,0);
    		} 
    		for(int i=1;i<=n;++i) build(rt[i],1,n,in[i]);
    		for(int i=1;i<=T;++i)
    		{
    			if(opt[i][0]=='A') 
    			{
    				x[i]=find(x[i]); y[i]=find(y[i]);
    				rt[x[i]]=merge(rt[x[i]],rt[y[i]],1,n);
    				fa[y[i]]=x[i];
    			} 
    			if(opt[i][0]=='Q')
    			{
    				if(dep[x[i]]<dep[y[i]]) swap(x[i],y[i]);
    				y[i]=find(y[i]);
    				printf("%lld
    ",(ask(rt[y[i]],1,in[x[i]]-1,1,n)+ask(rt[y[i]],out[x[i]]+1,n,1,n))*ask(rt[y[i]],in[x[i]],out[x[i]],1,n));
    			}
    		}
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    从零开始学安全(七)●Linux基础命令学习笔记
    从零开始学安全(六)●黑客常用的Dos命令
    ABAP
    ABAP modify screen:修改屏幕,实现隐藏、禁止输入字段
    C#以对象为成员的例子
    C#构造函数、属性的应用
    C#属性方法 构造函数(不知道自己理解的对不对)
    C#斐波那契数列求法(比较阶乘和循环所用时间)
    C#函数的递归
    C#函数的参数传递2(refout)
  • 原文地址:https://www.cnblogs.com/yspm/p/12682148.html
Copyright © 2011-2022 走看看