时间分治(线段树分治)

89 篇文章 0 订阅
72 篇文章 0 订阅

对于一类有插入、删除(撤销插入)和整体查询操作的题目,可以考虑按时间分治(也可以叫线段树分治),就是对于每一个插入操作处理出它存在的时间,那么就不用管删除操作了,再将这些插入操作存在区间建立一棵时间线段树,每个节点是一个vector,然后从线段树dfs到叶子经过的点上所有点vector的并就是在这个点时会对其产生影响的所有操作了。而一般这类题不会真的要把所有vector传到叶子,可能是线性基之类的东西往下传......

例题:

T1 bzoj4184 shallot

基本是模板了......

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define sc second
#define pb(x) push_back(x)
using namespace std;
const int N=5e5+100;
const int Mxa=1<<30;

void rd(int &x)
{
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+c-48,c=getchar();
	if(f)x=-x;
}

int n,a[N],ans[N];
struct xxj{
	int a[31];
	xxj(){memset(a,0,sizeof a);}
	int& operator[](int x)
	{return a[x];}
	void ins(int x)
	{
		for(int i=30,j=Mxa;i>=0;i--,j>>=1)
		{
			if(x&j)
			{
				if(!a[i]){a[i]=x;break;}
				x^=a[i];
			}
		}
	}
	int calc()
	{
		int nw=0;
		for(int i=30;i>=0;i--)
			if((nw^a[i])>nw)nw^=a[i];
		return nw;
	}
};

int fr_n,to_n;
pii fr[N],to[N];
vector<int>seg[N<<2];

void ins_seg(int L,int R,int l,int r,int k,int w)
{
	if(L<=l&&r<=R)seg[k].pb(w);
	else
	{
		int mid=(l+r)>>1;
		if(L<=mid)ins_seg(L,R,l,mid,k<<1,w);
		if(R>mid)ins_seg(L,R,mid+1,r,k<<1|1,w);
	}
}

void dfs_seg(int l,int r,int k,xxj res)
{
	for(int i=0;i<seg[k].size();i++)
		res.ins(seg[k][i]);
	if(l==r)
	{
		ans[l]=res.calc();
		return;
	}
	else
	{
		int mid=(l+r)>>1;
		dfs_seg(l,mid,k<<1,res);
		dfs_seg(mid+1,r,k<<1|1,res);
	}
}

int main()
{
	rd(n);
	for(int i=1;i<=n;i++)
		rd(a[i]);
	for(int i=1;i<=n;i++)
	{
		if(a[i]>0)fr[++fr_n]=pii(a[i],i);
		else to[++to_n]=pii(-a[i],i);
	}
	sort(fr+1,fr+fr_n+1),sort(to+1,to+to_n+1);
	int to_ps=0;
	for(int i=1;i<=fr_n;i++)
	{
		while(to_ps<=to_n&&fr[i].fi>to[to_ps].fi)++to_ps;
		//cerr<<fr[i].fi<<' '<<fr[i].sc<<' '<<to[to_ps].sc<<'\n';
		if(to_ps<=to_n&&fr[i].fi==to[to_ps].fi)
		{
			ins_seg(fr[i].sc,to[to_ps].sc-1,1,n,1,fr[i].fi);
			++to_ps;
		}
		else ins_seg(fr[i].sc,n,1,n,1,fr[i].fi);
	}
	dfs_seg(1,n,1,xxj());
	for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}

T2 bzoj4644经典傻逼题

刚开始没想到,其实边权可以异或丢到点权上去,这样选取一条边两个点根据异或操作特性贡献抵消刚好满足题目求割边要求,这样这题与上面基本一样了,把线性基内的东西改成bitset即可。

#include<bits/stdc++.h>
#define Bst bitset<1005>
using namespace std;
const int N=505,M=1005;

template<class T>
void rd(T &x)
{
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+c-48,c=getchar();
	if(f)x=-x;
}

struct xxj{
	Bst a[M];
	xxj(){};
	void ins(Bst x)
	{
		for(int i=M-1;i>=0;i--)
		{
			if(!x[i])continue;
			if(a[i].none()){a[i]=x;break;}
			x^=a[i];
		}
	}
	void print()
	{
		Bst res;
		res.reset();
		for(int i=M-1;i>=0;i--)
		{
			if(a[i].none())continue;
			if(!res[i])res^=a[i];
		}
		bool flg=0;
		for(int i=M-1;i>=0;i--)
		{
			if(!flg&&!res[i])continue;
			putchar(res[i]?'1':'0'),flg=1;
		}
		flg?puts(""):puts("0");
	}
};
Bst bf[N];
int n,m,las[N];
char s[M];
vector<Bst>seg[M<<2];

void ins_seg(int L,int R,int l,int r,int k,Bst x)
{
	if(L<=l&&r<=R)seg[k].push_back(x);
	else
	{
		int mid=(l+r)>>1;
		if(L<=mid)ins_seg(L,R,l,mid,k<<1,x);
		if(R>mid)ins_seg(L,R,mid+1,r,k<<1|1,x);
	}
}

void dfs_seg(int l,int r,int k,xxj res)
{
	for(int i=0;i<seg[k].size();i++)
		res.ins(seg[k][i]);
	if(l==r)res.print();
	else
	{
		int mid=(l+r)>>1;
		dfs_seg(l,mid,k<<1,res),dfs_seg(mid+1,r,k<<1|1,res);
	}
}

int main()
{
	//cerr<<sizeof seg;
	int ID,u,v,len;
	rd(ID);
	rd(n),rd(m);
	Bst nw;
	for(int tim=1;tim<=m;tim++)
	{
		rd(u),rd(v);
		scanf("%s",s+1);
		if(u==v)continue;
		len=strlen(s+1);
		nw.reset();
		for(int i=0;i<len;i++)
			nw[i]=(s[len-i]=='1'?1:0);
		if(las[u])ins_seg(las[u],tim-1,1,m,1,bf[u]);
		if(las[v])ins_seg(las[v],tim-1,1,m,1,bf[v]);
		las[u]=las[v]=tim;
		bf[u]^=nw,bf[v]^=nw;
	}
	for(int i=1;i<=n;i++)
		ins_seg(las[i],m,1,m,1,bf[i]);
	dfs_seg(1,m,1,xxj());
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值