[集训队作业2018]uoj 431 time map - 线段树

题目大意:给一个广义线段树(即分治中心是输入的),支持对一个节点代表的区间做区间与、或、异或一个数,以及询问从一个点向下走经过的点的权值和,一个点的权值定义为其所对应区间的区间与,向左还是向右走取决于该点权值中1的个数(即bitcount)。
题解:
考虑从一个点向下走,权值发生变化只会有log次。
先说一下某个std的做法:对这个广义线段树树剖,然后重链每个点维护其轻儿子的权值,链底维护自己的权值,那么每个点的权值就是到重链底的and。然后询问就暴力跳轻边,重链上线段树二分。修改一个点只会影响子子树和往上跳的重链链顶的父节点,修改维护一个区间and和区间or就能支持区间xor这个操作。
然而发现这个题线段树其实是假的,假设当前区间[L,R],现在往左走,那么直接线段树二分出最小的p使得[L,p]的and和[L,R]的and是一样的(这个p显然至少是R)。那么找到一个线段树上的节点[L,r]使得r>=p,那么一定是从[L,R]这个节点走到[L,r]这个节点然后再向左一步并且区间and变大。这样复杂度两个log。
这样做的另一个好处是可以支持对任意区间进行修改。
最后一提如何方便的实现一个比较难写的线段树。
将修改视为标记tag类,信息视为msg类,只需要考虑msg的合并、tag对msg的影响,tag和tag的合并即可。这样可以更加有条理的分析。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define uint unsigned lint
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
	const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;
	char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
	inline int inn()
	{
		int x,ch;while((ch=gc())<'0'||ch>'9');
		x=ch^'0';while((ch=gc())>='0'&&ch<='9')
			x=(x<<1)+(x<<3)+(ch^'0');return x;
	}
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
	char ss[100000*40],tt[40];int ssl,ttl;
	inline int print(lint x)
	{
		if(!x) ss[++ssl]='0';
		for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
		for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
	}
	inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
inline int bitcnt(uint x) { int c=0;while(x) c+=x&1,x>>=1;return c; }
const int N=1000010;pii rg[N<<1];
int ncnt,lc[N<<1],rc[N<<1],a[N];vector<pair<pii,int> > ID;
vector<int> vl[N],vr[N];int d[N<<1];
inline int build_tree(int l,int r,int dpt=1)
{
	int x=++ncnt;d[x]=dpt,vl[l].pb(r),vr[r].pb(l);
	rg[x]=mp(l,r),ID.pb(mp(rg[x],x));if(l==r) return x;int mid=inn();
	lc[x]=build_tree(l,mid,dpt+1),rc[x]=build_tree(mid+1,r,dpt+1);
	return x;
}
inline int id(pii rg) { return ID[lower_bound(ID.begin(),ID.end(),mp(rg,0))-ID.begin()].sec; }
inline uint clr(uint &x,uint y) { return x^=x&y; }
uint v;
struct tag{
	uint a,o,x;tag(uint _a=0,uint _o=0,uint _x=0) { a=_a,o=_o,x=_x; }
	inline tag& operator+=(const tag &t)
	{
		if(t.a) a|=t.a,clr(o,t.a),clr(x,t.a);
		if(t.o) o|=t.o,clr(a,t.o),clr(x,t.o);
		if(t.x) v=(a|o)&t.x,a^=v,o^=v,x^=t.x^v;
		return *this;
	}
	inline int empty()const { return (a|o|x)==0; }
	inline int clear() { return a=o=x=0,0; }
};
struct msg{
	uint a,o;
	msg(uint _a=0,uint _o=0) { a=_a,o=_o; }
	inline msg& operator+=(const tag &t)
	{
		if(t.a) clr(a,t.a),clr(o,t.a);
		if(t.o) a|=t.o,o|=t.o;
		if(t.x) v=(~(a^o))&t.x,a^=v,o^=v;
		return *this;
	}
	inline msg operator+(const msg v)const { return msg(a&v.a,o|v.o); }
	inline msg& operator=(int x) { return a=o=x,*this; }
};
struct segment{
	int l,r;msg v;tag t;segment *ch[2];
}*rt;
inline int push_up(segment* &rt) { return rt->v=rt->ch[0]->v+rt->ch[1]->v,0; }
inline int build(segment* &rt,int l,int r)
{
	rt=new segment,rt->l=l,rt->r=r;
	if(l==r) return rt->v=a[l],0;
	int mid=(l+r)>>1;
	build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
	return push_up(rt);
}
inline int update_tags(segment* &rt,const tag &t) { return rt->v+=t,rt->t+=t,0; }
inline int push_down(segment* &rt) { return update_tags(rt->ch[0],rt->t),update_tags(rt->ch[1],rt->t),rt->t.clear(); }
inline int update(segment* &rt,int s,int t,const tag &v)
{
	int l=rt->l,r=rt->r,mid=(l+r)>>1;
	if(s<=l&&r<=t) return update_tags(rt,v);
	if(!rt->t.empty()) push_down(rt);
	if(s<=mid) update(rt->ch[0],s,t,v);
	if(mid<t) update(rt->ch[1],s,t,v);
	return push_up(rt);
}
inline uint query(segment* &rt,int s,int t)
{
	int l=rt->l,r=rt->r,mid=(l+r)>>1;
	if(s<=l&&r<=t) return rt->v.a;
	if(!rt->t.empty()) push_down(rt);
	uint ans=-1;
	if(s<=mid) ans&=query(rt->ch[0],s,t);
	if(mid<t) ans&=query(rt->ch[1],s,t);
	return ans;
}
uint tot,now;int ps;
inline int queryl(segment* rt,int s,int t)
{
	if(~ps) return ps;
	int l=rt->l,r=rt->r,mid=(l+r)>>1;
	if(s<=l&&r<=t)
	{
		if((now&rt->v.a)!=tot) return now&=rt->v.a,ps;
		while(rt->l<rt->r)
		{
			push_down(rt);
			if((now&rt->ch[0]->v.a)!=tot)
				now&=rt->ch[0]->v.a,rt=rt->ch[1];
			else rt=rt->ch[0];
		}
		return ps=rt->l;
	}
	if(!rt->t.empty()) push_down(rt);
	if(s<=mid) queryl(rt->ch[0],s,t);
	if(mid<t) queryl(rt->ch[1],s,t);
	return ps;
}
inline int queryr(segment* rt,int s,int t)
{
	if(~ps) return ps;
	int l=rt->l,r=rt->r,mid=(l+r)>>1;
	if(s<=l&&r<=t)
	{
		if((now&rt->v.a)!=tot) return now&=rt->v.a,ps;
		while(rt->l<rt->r)
		{
			push_down(rt);
			if((now&rt->ch[1]->v.a)!=tot)
				now&=rt->ch[1]->v.a,rt=rt->ch[0];
			else rt=rt->ch[1];
		}
		return ps=rt->l;
	}
	if(!rt->t.empty()) push_down(rt);
	if(mid<t) queryr(rt->ch[1],s,t);
	if(s<=mid) queryr(rt->ch[0],s,t);
	return ps;
}
inline int qryl(vector<int> &v,int l,int p)
{
	return id(mp(l,v[lower_bound(v.begin(),v.end(),p)-v.begin()]));
}
inline int qryr(vector<int> &v,int p,int r)
{
	return id(mp(v[upper_bound(v.begin(),v.end(),p)-v.begin()-1],r));
}
int main()
{
	int n=inn(),q=inn();
	rep(i,1,n) a[i]=inn();
	build_tree(1,n);
	build(rt,1,n);
	rep(i,1,n) sort(vl[i].begin(),vl[i].end());
	sort(ID.begin(),ID.end());
	while(q--)
	{
		int tp=inn(),l=inn(),r=inn(),x;
		if(tp==1) x=inn(),update(rt,l,r,tag(~x,0,0));
		else if(tp==2) x=inn(),update(rt,l,r,tag(0,x,0));
		else if(tp==3) x=inn(),update(rt,l,r,tag(0,0,x));
		else{
			int x=id(mp(l,r));lint ans=0;
			while(x)
			{
				tot=query(rt,l=rg[x].fir,r=rg[x].sec);
				if(bitcnt(tot)&1)
				{
					now=-1,ps=-1;
					int p=queryl(rt,l,r),y=qryl(vl[l],l,p);
					ans+=tot*(d[y]-d[x]+1),x=lc[y];
				}
				else{
					now=-1,ps=-1;
					int p=queryr(rt,l,r),y=qryr(vr[r],p,r);
					ans+=tot*(d[y]-d[x]+1),x=rc[y];
				}
			}
			print(ans);
		}
	}
	return Flush(),0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/88086839