THUSC2015

这套题测得时候被暴虐了。。。


T1:  bzoj 4103: [Thu Summer Camp 2015]异或运算  http://www.lydsy.com/JudgeOnline/problem.php?id=4103 

这题是个水题,就是以Y数列建trie,然后对于每个询问,都枚举每个X去trie上跑,就OK了,复杂度O(nplog value)

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1011,maxm=300011;
inline int read(){
	int x=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x;
}
int n,m,a[maxn],b[maxm];
void init(){
	n=read(); m=read();
	for (int i=1;i<=n;++i) a[i]=read();
	for (int i=1;i<=m;++i) b[i]=read();
}
struct Ttrie{
	struct node{
		node *c[2]; int sum;
	}*null,e[12000000],*root[maxm];
	int tot;
	void clear(node &x){x.c[0]=x.c[1]=null; x.sum=0;}
	node *newnode(){clear(e[++tot]); return &e[tot];}
	void clear(){
		tot=0; null=e; null->c[0]=null->c[1]=null; null->sum=0;
		root[0]=newnode();
	}
	void ins(int w,int x){
		node *p=root[w]=newnode(),*lp=root[w-1];
		for (int i=30;i>=0;--i){
			bool s=(bool)((1<sum; p->c[s]=newnode();
			p=p->c[s]; lp=lp->c[s];
		}
		*p=*lp; ++p->sum;
	}
}t;
void prepare(){
	t.clear();
	for (int i=1;i<=m;++i) t.ins(i,b[i]);
}
struct Tq{
	int a,b,v;
	Tq(){}
	Tq(int a_,int b_,int v_):a(a_),b(b_),v(v_){}
};
int getans(int u,int d,int l,int r,int rank){
	static Tq q[maxn<<1]; int cnt=0,res=0;
	for (int i=u;i<=d;++i) q[++cnt]=Tq(i,l-1,-1);
	for (int i=u;i<=d;++i) q[++cnt]=Tq(i,r,1);
	static Ttrie::node *w[maxn<<1];
	for (int i=1;i<=cnt;++i) w[i]=t.root[q[i].b];
	for (int t=30;t>=0;--t){
		int sum=0;
		for (int i=1;i<=cnt;++i)
			sum+=q[i].v*w[i]->c[!(bool)((1<sum;
		if (sumc[(bool)((1<c[!(bool)((1<


T2:  bzoj 4105: [Thu Summer Camp 2015]平方运算  http://www.lydsy.com/JudgeOnline/problem.php?id=4105

这题非常神,深度膜拜了 http://blog.csdn.net/PoPoQQQ/article/details/46349249 之后,仍然什么都不懂,最后找PoPoQQQ问了一下,终于弄懂了  Orz

这题我们容易发现在平方时是有环的,然后发现给你的p的环长的lcm最大是60,到环的距离最大为11

于是我们维护一棵seg,每个节点有两种转态1:有点不在环上 2:所有点都在环上

第2种就在节点上维护一个链表,因为环的lcm<=60,所以链表长60就行了,update的时候把两个儿子的链表合并就是O(60nlogn)的

问题就在于第1种,如果在修改的时候碰到了第1种节点怎么打标记呢,大神给我的答案就是直接修改两个儿子,然后向上更新,这样的复杂度在一起最多是O(11nlogn)的(因为到环的距离不超过11),
于是这样复杂度就是O(60nlogn)的了

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100011,maxmod=10011,maxc=63;
int n,m,mod,a[maxn];
void init(){
	scanf("%d%d%d",&n,&m,&mod);
	for (int i=1;i<=n;++i) scanf("%d",a+i);
}
int next[maxmod]; bool Incir[maxmod];
void prepare(){
	static bool vis[maxmod]; memset(Incir,1,sizeof(Incir));
	for (int i=0;isum=l->sum+r->sum; x->Ici=l->Ici&r->Ici;
		if (x->Ici){
			x->len=lcm(l->len,r->len); 
			int tx=l->w,ty=r->w;
			for (int i=0;ilen;++i){
				x->cir[i]=l->cir[tx]+r->cir[ty];
				++tx; ++ty; if (tx==l->len) tx=0; if (ty==r->len) ty=0;
			}
			x->w=0;
		}
	}
	void pushdown(int p){
		if (!e[p].cov) return;
		node *x=e+p,*l=e+(p<<1),*r=l+1;
		int c=x->cov; x->cov=0; l->cov+=c; r->cov+=c;
		l->w+=c; if (l->w>=l->len) l->w%=l->len; l->sum=l->cir[l->w];
		r->w+=c; if (r->w>=r->len) r->w%=r->len; r->sum=r->cir[r->w];
	}
	void build(int p,int l,int r){
		if (l==r){e[p].init(a[l]); return;}
		int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);
		update(p);
	}
	void clear(){build(1,1,n);}
	
	void modify(int p,int l,int r,int fir,int las){
		if (l==fir && r==las && e[p].Ici){
			++e[p].cov; ++e[p].w; if (e[p].w==e[p].len) e[p].w=0;
			e[p].sum=e[p].cir[e[p].w]; return;
		}
		if (l==r){e[p].init(next[e[p].sum]); return;}
		pushdown(p); int mid=(l+r)>>1;
		if (las<=mid) modify(p<<1,l,mid,fir,las);
		else if (fir>mid) modify(p<<1|1,mid+1,r,fir,las);
		else modify(p<<1,l,mid,fir,mid),modify(p<<1|1,mid+1,r,mid+1,las);
		update(p);
	}
	int Query(int p,int l,int r,int fir,int las){
		if (l==fir && r==las) return e[p].sum;
		pushdown(p); int mid=(l+r)>>1;
		if (las<=mid) return Query(p<<1,l,mid,fir,las);
		if (fir>mid) return Query(p<<1|1,mid+1,r,fir,las);
		return Query(p<<1,l,mid,fir,mid)+Query(p<<1|1,mid+1,r,mid+1,las);
	}
	void modify(int l,int r){modify(1,1,n,l,r);}
	int Query(int l,int r){return Query(1,1,n,l,r);}
}seg;
void work(){
	prepare(); seg.clear();
	while (m--){
		int op,l,r; scanf("%d%d%d",&op,&l,&r);
		if (op) printf("%d\n",seg.Query(l,r));
		else seg.modify(l,r);
	}
}
int main(){
	init();
	work();
	return 0;
}

T3:  bzoj 4104: [Thu Summer Camp 2015]解密运算   http://www.lydsy.com/JudgeOnline/problem.php?id=4104

这题标程非常短,但就是不明觉厉,膜拜了PPS大神后弄懂了

首先如果各不相同那就非常水了,因为最左边一列就是最右边一列排序后的。问题就在于如果有相同的不知道谁是谁了,然而可以发现在左边以x开头的对应到右边来以x结尾的相对顺序是不会变的,于是又可以找到对应关系了,这样就很水了

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=200011;
int now=0,n,a[maxn];
void init(){
	scanf("%d%*d",&n); ++n;
	for (int i=1;i<=n;++i){
		scanf("%d",a+i);
		if (!a[i]) now=i;
	}
}
struct Tp{
	int v,pos;
	Tp(){}
	Tp(int v_,int pos_):v(v_),pos(pos_){}
}q[maxn];
inline bool cmp(Tp a,Tp b){return a.v


你可能感兴趣的:(可持久化数据结构,线段树,trie)