zoukankan      html  css  js  c++  java
  • HAOI2017 八纵八横——线段树分治+线性基

    题目大意

    给定一个图,每次加一些边,或者删掉一些后来加上去的边,定义一个环的价值为环上所有的边的异或和,重复走的边重复算。每次询问这个时刻图中的所有经过1号点的环的最大价值。

    思路

    首先考虑对于一个静态的图如何求解图中所有经过1号点的环的最大价值,发现这个经过1号点就是唬人的,图中任意一个环都可以经过1号点再走回来。

    于是题目变成了求解图中环的最大价值,可以将图中所有的简单环给拎出来放到线性基里面求最大价值,不难发现这是对的。

    然后题目转化为了如何求图中所有的简单环,一般我们可以直接对图dfs找环,这个题目可以随便建出一颗生成树,任何一条非树边都对应了一个简单环,于是我们每次只需要在树上加边删边即可。

    但是线性基不支持删除啊,线段树分治就好了。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.4.3
     * Problem : luogu3733
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    #define pii pair<bitset<maxn>,int>
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("luogu3733.in","r",stdin);
    	freopen("luogu3733.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    string proc(){
    	ifstream f("/proc/self/status");
    	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
    }
    
    const int maxn=1000+10;
    int n,m,q,tot;
    struct edge{
    	int u,v,l,r;
    	bitset<maxn>w;
    }e[maxn];
    vector<pii>G[maxn];
    vector<edge>lis;
    bitset<maxn>dis[maxn];
    
    void read_bitset(bitset<maxn>&x){
    	static char strbuf[maxn];
    	char ch=getchar(); int tp=0;
    	for(;!isdigit(ch);ch=getchar());
    	for(;isdigit(ch);ch=getchar())strbuf[tp++]=ch;
    	tot=max(tot,tp),x.reset();
    	DREP(i,tp-1,0)if(strbuf[tp-1-i]=='1')x.set(i);
    }
    
    void output(bitset<maxn>&x,char ch='
    '){
    	int p=0;
    	DREP(i,tot-1,0)if(x[i]){p=i;break;}
    	DREP(i,p,0)putchar(x[i]+48);
    	putchar(ch);
    }
    
    int fa[maxn];
    int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}
    
    void dfs_init(int u,int fh){
    	REP(i,0,G[u].size()-1){
    		bitset<maxn>w=G[u][i].fi;
    		int v=G[u][i].se;
    		if(v==fh)continue;
    		/*cout<<u<<" "<<v<<endl;
    		output(w);*/
    		dis[v]=dis[u]^w;
    		dfs_init(v,u);
    	}
    }
    
    struct liner_base{
    	bitset<maxn>b[maxn];
    	liner_base(){DREP(i,tot-1,0)b[i].reset();}
    	void insert(bitset<maxn>x){
    		DREP(i,tot-1,0)if(x[i]){
    			if(!b[i][i]){b[i]=x;break;}
    			x^=b[i];
    		}
    	}
    	bitset<maxn>query(){
    		bitset<maxn>ret(0);
    		DREP(i,tot-1,0)if(!ret[i] && b[i][i])
    			ret^=b[i];
    		return ret;
    	}
    }T[21];
    
    void init(){
    	read(n),read(m),read(q);
    	REP(i,1,n)fa[i]=i;
    
    	int u,v;
    	REP(i,1,m){
    		read(u),read(v),read_bitset(e[i].w);
    		e[i].u=u,e[i].v=v;
    		//output(e[i].w);
    		if(find(u)!=find(v)){
    			fa[find(u)]=find(v);
    			G[u].push_back(mk(e[i].w,v));
    			G[v].push_back(mk(e[i].w,u));
    		}
    		else lis.push_back(e[i]);
    	}
    
    	dfs_init(n,0);
    }
    
    #define mid ((l+r)>>1)
    #define lc (o<<1)
    #define rc (o<<1|1)
    #define lson lc,l,mid
    #define rson rc,mid+1,r
    
    vector<bitset<maxn> >t[maxn<<2];
    void insert(int o,int l,int r,int L,int R,bitset<maxn>&x){
    	if(L<=l && r<=R)t[o].push_back(x);
    	else{
    		if(L<=mid)insert(lson,L,R,x);
    		if(R>=mid+1)insert(rson,L,R,x);
    	}
    }
    
    void divide(int o,int l,int r,int dep){
    	REP(i,0,t[o].size()-1)
    		T[dep].insert(t[o][i]);
    	if(l==r){
    		bitset<maxn>ans=T[dep].query();
    		output(ans);
    	}
    	else{
    		T[dep+1]=T[dep];
    		divide(lson,dep+1);
    		T[dep+1]=T[dep];
    		divide(rson,dep+1);
    	}
    }
    
    vector<edge>tl[maxn];
    void work(){
    	char opt[11];
    	int u,v,cnt=0;
    	bitset<maxn>w;
    	REP(i,0,lis.size()-1){
    		w=dis[lis[i].u]^dis[lis[i].v]^lis[i].w;
    		insert(1,1,q+1,1,q+1,w);
    	}
    	REP(i,1,q){
    		scanf("%s",opt);
    		if(opt[0]=='A'){
    			read(u),read(v),read_bitset(w);
    			tl[++cnt].push_back((edge){u,v,i+1,q+1,w});
    		}
    		else if(opt[1]=='h'){
    			read(u),read_bitset(w);
    			int las=tl[u].size()-1;
    			tl[u][las].r=i;
    			tl[u].push_back((edge){tl[u][las].u,tl[u][las].v,i+1,q+1,w});
    		}
    		else{
    			read(u);
    			int las=tl[u].size()-1;
    			tl[u][las].r=i;
    		}
    	}
    	REP(i,1,cnt)REP(j,0,tl[i].size()-1){
    		w=dis[tl[i][j].u]^dis[tl[i][j].v]^tl[i][j].w;
    		insert(1,1,q+1,tl[i][j].l,tl[i][j].r,w);
    	}
    	divide(1,1,q+1,0);
    }
    
    int main(){
    	File();
    
    	init();
    
    	work();
    
    	return 0;
    }
    
    
  • 相关阅读:
    Boost练习程序(强制转换)
    4873279(1002)
    A+B Problem(1000)
    STL练习程序(去除相同元素)
    Boost练习程序(智能指针)
    Sql技巧总结
    MySql Show Status详解
    mysql show status调优
    mysql decimal、numeric数据类型
    Apache Thrift学习小记
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10647955.html
Copyright © 2011-2022 走看看