Pluto_Rabbit's Blog

蒟蒻妹纸一枚,轻拍

【学习】线段树

Jacinth posted @ 2016年7月14日 12:12 in Lerning with tags 学习 线段树 Learning bzoj , 685 阅读

感觉自己虽然在学习树剖的时候学习了线段树(这什么学习过程?

但是感觉自己还有很多姿势不够

所以先做几道题吧

No. 算法 状态
1012 树状数组/线段树/RMQ Accepted
1798 线段树 Accepted
3212 Splay/线段树区间操作 Accepted
3226 线段树 Accepted
4364 线段树 Accepted
3685 线段树 Accepted
3813 线段树+逆元 Accepted
2962 线段树 Accepted
1067 线段树分类讨论 Accepted
4373 线段树 Accepted
1858 线段树各种操作 Accepted

update20170112: 新增一道各种操作的题目:BZOJ1858

update20161108: 修修补补地到了10题

竟然才做了9道QAQ

连两位数都没上 羞耻.jpg

1012: [JSOI2008]最大数maxnumber

比较简单的线段树吧

也没有太复杂的标记什么的

真是简单粗暴

听说还有单调栈和单调队列的做法,真刺激

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define MM 200020
using namespace std;
char ch[10];
int mx[MM*4],a[MM];
int la,l,n,m,t,d,mm;
void change(int ll,int rr,int st)
{
	if (ll==rr)	{	mx[st]=n;	return;	}
	int mid=(ll+rr)/2;
	if (l<=mid) change(ll,mid,st<<1);
		else change(mid+1,rr,(st<<1)+1);
	mx[st]=max(mx[st<<1],mx[(st<<1)+1]);
	return;
}
int check(int ll,int rr,int l,int r,int st)
{
	if (ll<=l&&rr>=r) return mx[st];
	int sum=0,mid=(l+r)/2;
	if (ll<=mid) sum=max(sum,check(ll,rr,l,mid,st<<1));
	if (rr>mid) sum=max(sum,check(ll,rr,mid+1,r,(st<<1)+1));
	return sum;
}
int main()
{
	scanf("%d%d",&m,&d);
	t=l=0;
	mm=m;
	memset(mx,0,sizeof(mx));
	while (m--)
	{
		scanf("%s%d",&ch,&n);
		l++;
		if (ch[0]=='A')
		{
			a[++la]=l;	n=(n%d+t%d)%d;	change(1,mm,1);
		}
		else
		{	printf("%d\n",t=check(a[la-n+1],a[la],1,mm,1));
			t%=d;		}
	}
	return 0;
}

1798: [Ahoi2009]Seq 维护序列seq

其实和黈力上课讲的某一题差不多的吧

但标记不能永久化

要维护两个tag

调的累炸了

听说窝的程序跑得比xmc快?!(但人家的程序短啊!

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;

#define NN 100005
#define LL long long

struct Tree
{
	int l,r;
	LL t1,t2,sum;
}tr[NN<<2];
int n,m,mod,op,l,r,x,a[NN];

void Build(int p,int l,int r)
{
	tr[p].l = l, tr[p].r = r, tr[p].t1 = 0, tr[p].t2 = 1;
	if (l == r) { tr[p].sum = a[l] % mod; return; }
	int mid = (l+r) >> 1;
	Build(p<<1,l,mid); Build(p<<1|1,mid+1,r);
	tr[p].sum = (tr[p<<1].sum + tr[p<<1|1].sum) % mod;
}

void push_down(int num)  
{  
    if (tr[num].t2==1&&tr[num].t1==0) return;  
    tr[num*2].t1=(tr[num*2].t1*tr[num].t2+tr[num].t1)%mod;  
    tr[num*2+1].t1=(tr[num*2+1].t1*tr[num].t2+tr[num].t1)%mod;  
    tr[num*2].t2=(tr[num*2].t2*tr[num].t2)%mod;  
    tr[num*2+1].t2=(tr[num*2+1].t2*tr[num].t2)%mod;  
    tr[num*2].sum=(tr[num*2].sum*tr[num].t2+(tr[num*2].r-tr[num*2].l+1)*tr[num].t1)%mod;  
    tr[num*2+1].sum=(tr[num*2+1].sum*tr[num].t2+(tr[num*2+1].r-tr[num*2+1].l+1)*tr[num].t1)%mod;  
    tr[num].t1=0;  
    tr[num].t2=1;  
    return;  
}  

void mul(int p,int l,int r,int xx)
{
	if (tr[p].l > r || tr[p].r < l) return;
	if (tr[p].l >= l && tr[p].r <= r)
	{
		tr[p].t1 = tr[p].t1 * xx % mod;
		tr[p].t2 = tr[p].t2 * xx % mod;
		tr[p].sum = tr[p].sum * xx % mod;
		return;
	}
	push_down(p);
	mul(p<<1,l,r,xx); mul(p<<1|1,l,r,xx);
	tr[p].sum = (tr[p<<1].sum + tr[p<<1|1].sum) % mod;
	return;
}
void add(int p,int l,int r,int xx)
{
	if (tr[p].l > r || tr[p].r < l) return;
	if (tr[p].l >= l && tr[p].r <= r)
	{
		tr[p].t1 = (tr[p].t1 + xx) % mod;
		tr[p].sum = (tr[p].sum + (tr[p].r - tr[p].l + 1)*xx % mod) % mod;
		return;
	}
	push_down(p);
	add(p<<1,l,r,xx); add(p<<1|1,l,r,xx);
	tr[p].sum = (tr[p<<1].sum + tr[p<<1|1].sum) % mod;
	return;
}

LL query(int p,int l,int r)
{
	if (tr[p].l > r || tr[p].r < l) return 0;
	if (tr[p].l >= l && tr[p].r <= r) return tr[p].sum % mod;
	push_down(p);
	return (query(p<<1,l,r) + query(p<<1|1,l,r)) % mod;
}

int main()
{
	scanf("%d%d",&n,&mod);
	for (int i=1;i<=n;++i) scanf("%d",&a[i]);
	Build(1,1,n);
	scanf("%d",&m);
	while (m--)
	{
		scanf("%d",&op);
		switch (op)
		{
			case 1:
				scanf("%d%d%d",&l,&r,&x);
				mul(1,l,r,x);
				break;
			case 2:
				scanf("%d%d%d",&l,&r,&x);
				add(1,l,r,x);
				break;
			case 3:
				scanf("%d%d",&l,&r);
				printf("%d\n",query(1,l,r)%mod);
				break;
		}
	}
	return 0;
}

3212: Pku3468 A Simple Problem with Integers

维护线段树,区间加,区间求和

注意long long

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;

#define LL long long
#define NN 100005

int n,m,x,y,z;
char ch[10];
struct Tree
{
	LL s,ad;
	int l,r;
}tr[NN<<2];

void push_up(int p)
{
	tr[p].s = tr[p<<1].s + tr[p<<1|1].s;
}

void push_down(int p)
{
	if (tr[p].l == tr[p].r) return;
	if (tr[p].ad)
	{
		tr[p<<1].ad += tr[p].ad, tr[p<<1|1].ad += tr[p].ad;
		tr[p<<1].s += tr[p].ad * (tr[p<<1].r - tr[p<<1].l + 1);
		tr[p<<1|1].s += tr[p].ad * (tr[p<<1|1].r - tr[p<<1|1].l + 1);
		tr[p].ad = 0;
	}
}

void Build(int p,int l,int r)
{
	tr[p].l = l, tr[p].r = r;
	if (l == r) { scanf("%lld",&tr[p].s); return;}
	int mid = (l+r) >> 1;
	Build(p<<1,l,mid); Build(p<<1|1,mid+1,r);
	push_up(p);
}

void Add(int p,int L,int R,int v)
{
	push_down(p);
	int l = tr[p].l, r = tr[p].r, sum = (r-l+1), mid = (l+r) >> 1;
	if (l == L && R == r) { tr[p].s += (LL) v * sum, tr[p].ad += v; return;	}
	if (mid >= R) Add(p<<1,L,R,v);
	else if (mid < L) Add(p<<1|1,L,R,v);
	else Add(p<<1,L,mid,v), Add(p<<1|1,mid+1,R,v);
	push_up(p);
}

LL Query(int p,int L,int R)
{
	push_down(p);
	int l = tr[p].l, r = tr[p].r, mid = (l+r) >> 1;
	if (l == L && R == r) return tr[p].s;
	if (mid >= R) return Query(p<<1,L,R);
	else if (mid < L) return Query(p<<1|1,L,R);
	else return Query(p<<1,L,mid) + Query(p<<1|1,mid+1,R);
}

int main()
{
	scanf("%d%d",&n,&m);
	Build(1,1,n);
	while (m--)
	{
		scanf("%s",ch);
		if (ch[0] == 'Q')
		{
			scanf("%d%d",&x,&y);
			printf("%lld\n",Query(1,x,y));
		}
		else
		{
			scanf("%d%d%d",&x,&y,&z);
			Add(1,x,y,z);
		}
	}
	return 0;
}

3226: [Sdoi2008]校门外的区间

每个数之间加入一个数,就像这样
[2,3) -> [2,2.5]
(3,4] -> [3.5,4]
似乎就真的方便了好多哎
U 区间涂1;
I 两侧区间涂0;
D 区间涂0;
C 两侧涂0,中间取反;
S 区间取反;
bingo
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;

char ch[10];
#define N 131073
struct Tree
{
	int l,r,val,tag,rev;
}tr[N<<2];
int x,y,st,la,flag;

int read()
{
    int x=0,f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='(')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	if(ch==')')f=1;
    return x*2-f;
}

void Build(int p,int l,int r)
{
	tr[p].l = l, tr[p].r = r, tr[p].tag = -1;
	if (l == r) return;
	int mid = (l+r) >> 1;
	Build(p<<1,l,mid); Build(p<<1|1,mid+1,r);
}
void push_down(int p)
{
	int tag = tr[p].tag, rev = tr[p].rev;
	tr[p].tag = -1, tr[p].rev = 0;
	if (tr[p].l == tr[p].r)
	{
		if (tag != -1) tr[p].val = tag;
		tr[p].val ^= rev;
		return;
	}
	if (tag != -1)
	{
		tr[p<<1].tag = tr[p<<1|1].tag = tag;
		tr[p<<1].rev = tr[p<<1|1].rev = 0;
	}
	tr[p<<1].rev ^= rev, tr[p<<1|1].rev ^= rev;
}

int Query(int p,int xx)
{
	push_down(p);
	int l = tr[p].l, r = tr[p].r, mid = (l+r) >> 1;
	if (l == r) return tr[p].val;
	if (xx<=mid) return Query(p<<1,xx); else return Query(p<<1|1,xx);
}
void Modify(int p,int L,int R,int v)
{
	if (R<L) return;
	push_down(p);
	int l = tr[p].l, r = tr[p].r, mid = (l+r) >> 1;
	if (l == L && R == r)
	{
		if (v == -1) tr[p].rev ^= 1; else tr[p].tag = v;
		return;
	}
	if (R <= mid) Modify(p<<1,L,R,v);
	else if (L > mid) Modify(p<<1|1,L,R,v);
	else Modify(p<<1,L,mid,v), Modify(p<<1|1,mid+1,R,v);
}

void Rev(int p,int L,int R) { Modify(p,L,R,-1);}

int main()
{
	Build(1,1,N);
	while (scanf("%s",ch) != EOF)
	{
		x = read(), y = read();
		x += 2; y += 2;
		switch (ch[0])
		{
			case 'U': Modify(1,x,y,1); break;
			case 'I': Modify(1,1,x-1,0); Modify(1,y+1,N,0); break;
			case 'D': Modify(1,x,y,0); break;
			case 'C': Modify(1,1,x-1,0); Modify(1,y+1,N,0); Rev(1,x,y); break;
			case 'S': Rev(1,x,y); break;
		}
	}
	st = la = -1; flag = 0;
	for (int i=1;i<=N;++i)
	if (Query(1,i))
	{
		if (st == -1) st = i;
		la = i;
	}
	else
	{
		if (st != -1)
		{
			if (flag) printf(" ");	else flag = 1;
			if (st & 1) printf("("); else printf("[");
			printf("%d,%d",st/2-1,(la+1)/2-1);
			if (la & 1) printf(")"); else printf("]");
		}
		la = st = -1;
	}
	if (!flag) puts("empty set");
	return 0;
}

4364: [IOI2014]wall砖墙

线段树乱搞..乱更新一下QAQ

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

#define NN 2000010
int n,m,op,l,r,x,mx1[NN<<2],mx2[NN<<2];

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void push_down(int p)
{
	int l = p<<1, r = p<<1|1;
	if (mx2[p] > mx1[l]) mx1[l] = mx2[l] = mx2[p]; else if (mx2[p] > mx2[l]) mx2[l] = mx2[p];
	if (mx2[p] > mx1[r]) mx1[r] = mx2[r] = mx2[p]; else if (mx2[p] > mx2[r]) mx2[r] = mx2[p];
	if (mx1[p] < mx2[l]) mx1[l] = mx2[l] = mx1[p]; else if (mx1[p] < mx1[l]) mx1[l] = mx1[p];
	if (mx1[p] < mx2[r]) mx1[r] = mx2[r] = mx1[p]; else if (mx1[p] < mx1[r]) mx1[r] = mx1[p];
}

inline void push_up(int p)
{
	mx1[p] = max(mx1[p<<1],mx1[p<<1|1]);
	mx2[p] = min(mx2[p<<1],mx2[p<<1|1]); 
}

inline void Update1(int L,int R,int l,int r,int p,int xx)
{
	if (L == l && R == r) { mx1[p] = max(mx1[p],xx), mx2[p] = max(mx2[p],xx); return;}
	int mid = (l+r) >> 1;
	push_down(p);
	if (R <= mid) Update1(L,R,l,mid,p<<1,xx);
	else if (L > mid) Update1(L,R,mid+1,r,p<<1|1,xx);
	else Update1(L,mid,l,mid,p<<1,xx), Update1(mid+1,R,mid+1,r,p<<1|1,xx);
	push_up(p);
}

inline void Update2(int L,int R,int l,int r,int p,int xx)
{
	if (L == l && R == r) { mx1[p] = min(mx1[p],xx), mx2[p] = min(mx2[p],xx); return;}
	int mid = (l+r) >> 1;
	push_down(p);
	if (R <= mid) Update2(L,R,l,mid,p<<1,xx);
	else if (L > mid) Update2(L,R,mid+1,r,p<<1|1,xx);
	else Update2(L,mid,l,mid,p<<1,xx), Update2(mid+1,R,mid+1,r,p<<1|1,xx);
	push_up(p);
}

inline void Build(int p,int l,int r)
{
	if (l == r)	{ printf("%d\n",mx1[p]); return; }
	int mid = (l+r) >> 1;
	push_down(p);
	Build(p<<1,l,mid), Build(p<<1|1,mid+1,r);
}

int main()
{
	n = read(), m = read();
	while (m--)
	{
		op = read();
		if (op == 1)
		{
			l = read(), r = read(), x = read();
			++l ,++r;
			Update1(l,r,1,n,1,x);
		}
		else
		{
			l = read(), r = read(), x = read();
			++l ,++r;
			Update2(l,r,1,n,1,x);
		}
	}
	Build(1,1,n);
	return 0;
}

3685: 普通van Emde Boas树

听说某Treap会被卡(反正不会写

糊里糊涂学习了一下zkw线段树的技巧 并没有完全弄会哎

在题解的帮助下终于写好了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
using namespace std;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,x,M = 0,cnt = 0,op;
bool tr[1<<21|1];

inline void Update(int xx,int d)
{
	if (!(d ^ tr[xx+M])) return;
	cnt += d ? 1 : -1;
	for (tr[xx+=M] = d, xx >>= 1;xx;xx >>= 1) tr[xx] = tr[xx<<1] | tr[xx<<1|1];
}
inline int Get_min(int xx)
{
	if (!cnt) return 0;
	for (;xx <= M;xx = tr[xx<<1] ? (xx<<1) : (xx<<1|1));
	return xx - M;
}
inline int Get_max(int xx)
{
	if (!cnt) return 0;
	for (;xx <= M;xx = tr[xx<<1|1] ? (xx<<1|1) : (xx<<1));
	return xx - M;
}
inline int Pre(int xx)
{
	if (!cnt) return 0;
	for (xx += M;xx != 1;xx >>= 1)
	if (xx & 1 && tr[xx^1])
	{
		xx ^= 1; break;
	}
	if (xx == 1) return 0;
	return Get_max(xx);
}
inline int Nxt(int xx)
{
	if (!cnt) return 0;
	for (xx += M;xx != 1;xx >>= 1)
	if (!(xx & 1) && tr[xx^1])
	{
		xx ^= 1; break;
	}
	if (xx == 1) return 0;
	return Get_min(xx);
}
inline void Judge(int xx)
{
	printf(tr[xx+M] ? "1\n" : "-1\n");
}

int main()
{
	n = read(), m = read();
	while ((1<<M) < n) M++;
	M = (1<<M) - 1;
	for (int i=1;i<=m;++i)
	{
		op = read();
		switch (op)
		{
			case 1: x = read() + 1; Update(x,1); break;
			case 2: x = read() + 1; Update(x,0); break;
			case 3: printf("%d\n",Get_min(1)-1); break;
			case 4: printf("%d\n",Get_max(1)-1); break;
			case 5: x = read() + 1; printf("%d\n",Pre(x) - 1); break;
			case 6: x = read() + 1; printf("%d\n",Nxt(x) - 1); break;
			case 7: x = read() + 1; Judge(x); break;
		}
	}
	return 0;
}

3813: 奇数国

感觉乱七八糟的东西捏在一起就会好烦啊呜呜呜

并不喜欢想怎么弄标记,然而不想怎么弄标记就做不出题呜呜呜

用两棵线段树,一棵维护乘积,一棵维护质因数(类似于状压压起来

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

#define N 305
#define mod 19961993
#define LL long long

LL bin[65],ni[N];
int n,pri[N]={0};
bool mark[N]={0};
struct Tree
{
	int l,r;
	LL v;
}tr[2][400010];

void Cal(int f,int k,int val)
{
	if (f == 0) tr[f][k].v = val;
	else
	{
		tr[f][k].v = 0;
		for (int i=1;i<=60;++i)
			if (val % pri[i] == 0) tr[f][k].v += bin[i-1];
	}
}

void update(int f,int p)
{
	if (f == 0) tr[f][p].v = tr[f][p<<1].v * tr[f][p<<1|1].v % mod;
	else tr[f][p].v = tr[f][p<<1].v | tr[f][p<<1|1].v;
}

void Build(int f,int p,int l,int r)
{
	tr[f][p].l = l, tr[f][p].r = r;
	int mid = (l+r) >> 1;
	if (l == r)
	{
		Cal(f,p,3); return;
	}
	Build(f,p<<1,l,mid), Build(f,p<<1|1,mid+1,r);
	update(f,p);
}

void Pre()
{
	ni[1] = 1;
	for (int i=2;i<=300;++i)
	{
		ni[i] = -mod/i * ni[mod%i] % mod;
		if (!mark[i]) pri[++pri[0]] = i;
		for (int j=1;j<=pri[0] && i*pri[j]<=300;++j)
		{
			mark[i*pri[j]] = 1;
			if (i%pri[j] == 0) break;
		}
	}
	bin[0] = 1;
	for (int i=1;i<=60;++i) bin[i] = bin[i-1] << 1;
	Build(0,1,1,100000); Build(1,1,1,100000);
}

LL que(int f,int p,int x,int y)
{
	int l = tr[f][p].l, r = tr[f][p].r, mid = (l+r) >> 1;
	if (l == x && r == y) return tr[f][p].v;
	if (y<=mid) return que(f,p<<1,x,y);
	else if (x > mid) return que(f,p<<1|1,x,y);
	else
	{
		if (f == 0) return que(f,p<<1,x,mid) * que(f,p<<1|1,mid+1,y) % mod;
		else return que(f,p<<1,x,mid) | que(f,p<<1|1,mid+1,y);
	}
}

int Query(int xx,int yy)
{
	LL tmp1 = que(0,1,xx,yy), tmp2 = que(1,1,xx,yy);
	for (int i=1;i<=60;++i)
		if (tmp2 & bin[i-1]) tmp1 = tmp1*(pri[i]-1) % mod * ni[pri[i]] %mod;
	tmp1 = (tmp1 + mod) % mod;
	return tmp1;
}

void Change(int f,int p,int xx,int val)
{
	int l = tr[f][p].l ,r = tr[f][p].r, mid = (l+r) >>1;
	if (l == r)
	{
		Cal(f,p,val); return;
	}
	if (xx<=mid) Change(f,p<<1,xx,val);
	else Change(f,p<<1|1,xx,val);
	update(f,p);
}
int main()
{
	Pre();
	n = read();
	for (int i=1;i<=n;++i)
	{
		int op = read(), x = read(), y = read();
		if (op == 0) printf("%d\n",Query(x,y));
		else Change(0,1,x,y), Change(1,1,x,y);
	}
	return 0;
}

2962: 序列操作

调得崩溃啊

最后错在把 p<<1|1 打成了p<<1 要死

用f[i]表示选i个数所有方案和,rt.f[i]=∑ij=0 ls.f[j] ∗ rs.f[i−j]

然后注意一点f[0]=1
对于第一种操作加k我们发现对答案f[i]会变为∑ij=0f[j]∗Cin−j∗ki−j
对于第二种操作取反,我们发现只有当c为奇数时答案会取反,这个也很好搞
然后就是打两个标记rev和add的线段树
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

#define NN 60050
#define mod 19940417
#define LL long long
int a[NN],b[25],c[NN][25],add[NN<<2],rev[NN<<2];
int n,q,x,y,z;
char ch[10];
struct Tree
{
	int f[25];
}tr[NN<<2];
int read() 
{
	bool f; char ch; int x;
	for (f=0,ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=1;
	for (x=0;ch>='0';ch=getchar()) x=x*10+ch-'0'; if (f) x=-x; 
	return x;
}
void Update(int &xx,int yy)
{
	xx += yy;
	if (xx >= mod) xx -= mod;
	if (xx < 0) xx += mod;
}

void Cal(int p,int l,int r,int xx)
{
	for (int i=1;i<=20;++i)
	{
		int tmp =0, tx = 1;
		for (int j=i;j>=0;--j)
		{
			Update(tmp,(LL)tr[p].f[j] * c[r-l+1-j][i-j] % mod * tx %mod);
			tx = (LL) tx * xx % mod;
		}
		b[i] = tmp;
	}
	for (int i=1;i<=20;++i) tr[p].f[i] = b[i];
}
void push_down(int p,int l,int r)
{
	if (rev[p])
	{
		rev[p<<1] ^= 1, rev[p<<1|1] ^= 1;
		for (int i=1;i<=20;i+=2) tr[p<<1].f[i] = (mod - tr[p<<1].f[i]) % mod;
		for (int i=1;i<=20;i+=2) tr[p<<1|1].f[i] = (mod - tr[p<<1|1].f[i]) % mod;
		add[p<<1] = (mod - add[p<<1]) % mod, add[p<<1|1] = (mod - add[p<<1|1]) % mod;
		rev[p] = 0;
	}
	if (add[p])
	{
		int mid = (l+r) >> 1;
		Update(add[p<<1],add[p]), Update(add[p<<1|1],add[p]);
		Cal(p<<1,l,mid,add[p]), Cal(p<<1|1,mid+1,r,add[p]);
		add[p] = 0;
	}
}
void push_up(int p)
{
	for (int i=1;i<=20;++i) tr[p].f[i] = 0;
	for (int i=0;i<=20;++i)
		for (int j=0;i+j <= 20;++j)
		{
			if (i+j == 0) continue;
			Update(tr[p].f[i+j],(LL)tr[p<<1].f[i] * tr[p<<1|1].f[j] % mod);
		}
}
void Build(int p,int l,int r)
{
	tr[p].f[0] = 1;
	if (l == r)	{ tr[p].f[1] = a[l]; return; }
	int mid = (l+r) >> 1;
	Build(p<<1,l,mid), Build(p<<1|1,mid+1,r);
	push_up(p);
}

void Inc(int p,int l,int r,int L,int R,int x)
{
	if (L <= l && R >= r) {	Update(add[p],x); Cal(p,l,r,x); return;	}
	int mid = (l+r) >> 1;
	push_down(p,l,r);
	if (L <= mid) Inc(p<<1,l,mid,L,R,x);
	if (R > mid) Inc(p<<1|1,mid+1,r,L,R,x);
	push_up(p);
}
void Rev(int p,int l,int r,int L,int R)
{
	if (L <= l && R >= r)
	{
		rev[p] ^= 1;
		add[p] = (mod - add[p]) % mod;
		for (int i=1;i<=20;i+=2) tr[p].f[i] = (mod - tr[p].f[i]) % mod;
		return;
	}
	int mid = (l+r) >> 1;
	push_down(p,l,r);
	if (L <= mid) Rev(p<<1,l,mid,L,R);
	if (R > mid) Rev(p<<1|1,mid+1,r,L,R);
	push_up(p);
}

Tree Ask(int p,int l,int r,int L,int R)
{
	if (L <= l && R >= r) return tr[p];
	push_down(p,l,r);
	int mid = (l+r) >>1;
	Tree t,t1,t2;
	if (L > mid) t = Ask(p<<1|1,mid+1,r,L,R);
	else if (R <= mid) t = Ask(p<<1,l,mid,L,R);
	else
	{
		t.f[0] = 1;
		for (int i=1;i<=20;++i) t.f[i] = 0;
		t1 = Ask(p<<1,l,mid,L,mid), t2 = Ask(p<<1|1,mid+1,r,mid+1,R);
		for (int i=0;i<=20;++i)
			for (int j=0;j+i <= 20;++j)
			{
				if (i+j == 0) continue;
				Update(t.f[i+j],(LL)t1.f[i] * t2.f[j] % mod);
			}
	}
	return t;
}  

int main()
{
	n = read(), q = read();
	for (int i=0;i<=n;++i)
	{
		c[i][0] = c[i][i] = 1;
		for (int j=1;j<i;++j) c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
	}
	for (int i=1;i<=n;++i) a[i] = read(), a[i] = (a[i] % mod + mod) %mod;
	Build(1,1,n);
	while (q--)
	{
		scanf("%s",ch);
		if (ch[0] == 'I')
		{
			x = read(), y =read(), z = read();
			z = (z%mod+mod)%mod;
			Inc(1,1,n,x,y,z);
		}
		else if (ch[0] == 'R')
		{
			x = read(), y = read();
			Rev(1,1,n,x,y);
		}
		else
		{
			x = read(), y = read(), z = read();
			z = (z%mod+mod)%mod;
			Tree tmp = Ask(1,1,n,x,y);
			printf("%d\n",tmp.f[z] % mod);
		}
	}
	return 0;
}

1067: [SCOI2007]降雨量

错误有危险,分类需谨慎

分类讨论都有毒,剧毒

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
#define lk k<<1
#define rk k<<1|1
using namespace std;
int n,m;
struct TREE
{
    int ly,ry,mx,f;
}tr[200001];
void read(int &xx)
{
    bool f=0; char CH;
    for (CH=getchar();CH<'0'||CH>'9';CH=getchar()) if (CH=='-') f=1;
    for (xx=0;CH>='0';CH=getchar()) xx=xx*10+CH-'0'; if (f) xx=-xx;
}
void Build(int k,int l,int r)
{
    if (l==r) { read(tr[k].ly), read(tr[k].mx); tr[k].ry=tr[k].ly; tr[k].f=1; return; }
    int mid=(l+r)>>1;
    Build(lk,l,mid), Build(rk,mid+1,r);
    tr[k].f=(tr[lk].f && tr[rk].f);
    if (tr[lk].ry+1!=tr[rk].ly) tr[k].f=0;
    tr[k].ly=tr[lk].ly, tr[k].ry=tr[rk].ry, tr[k].mx=max(tr[lk].mx,tr[rk].mx);
}
int Get(int k,int xx)
{
    if (tr[k].ly==tr[k].ry)
    {
        if (tr[k].ly!=xx) return 0; else return tr[k].mx;
    }
    if (xx<=tr[lk].ry) return Get(lk,xx);
    else if (xx>=tr[rk].ly) return Get(rk,xx);
    return 0;
}
int Getne(int k,int xx)
{
    int l=tr[k].ly, r=tr[k].ry;
    if (l==r) return tr[k].ly;
    if (xx<tr[lk].ry) return Getne(lk,xx);
    else return Getne(rk,xx);
}
int Getla(int k,int xx)
{
    int l=tr[k].ly, r=tr[k].ry;
    if (l==r) return tr[k].ly;
    if (xx>tr[rk].ly) return Getla(rk,xx);
    else return Getla(lk,xx);
}
int Ask(int k,int xx,int yy,int num)
{
    bool flag=0;
    if (xx<tr[k].ly) flag=1, xx=tr[k].ly;
    if (tr[k].ly==xx & tr[k].ry==yy)
    { if (tr[k].mx>=num) return 0; else if (tr[k].f&& !flag) return 1; else return 2;    }
    if (yy<=tr[lk].ry) { return Ask(lk,xx,yy,num);}
    else if (xx>=tr[rk].ly) { return Ask(rk,xx,yy,num);}
    else
    {
        int ta=Ask(lk,xx,tr[lk].ry,num);
        int tb=Ask(rk,tr[rk].ly,yy,num);
        if (!ta || !tb) return 0;
        else if (tr[lk].ry+1 != tr[rk].ly) return 2; else return 1;
    }
}
int main()
{
    read(n);
    Build(1,1,n);
    read(m);
    int ll,rr;
    for (int i=1;i<=m;++i)
    {
        read(ll), read(rr);
        if (rr<ll) { puts("false"); continue;}
        int lnum=Get(1,ll), rnum=Get(1,rr);
        if (!lnum && !rnum) {   puts("maybe"); continue; }
        else
        {
            int st=Getne(1,ll), en=Getla(1,rr);
            if (!lnum)
            {
                if (st>en || rr==en) { puts("maybe"); continue;  }
                int flag=Ask(1,st,en,rnum);
                if (!flag) puts("false"); else puts("maybe"); continue;
            }
            else if (!rnum)
            {
                if (st>en || ll==st) { puts("maybe"); continue; }
                int flag=Ask(1,st,en,lnum);
                if (!flag) puts("false"); else puts("maybe"); continue;
            }
            else
            {
                if (rnum>lnum) { puts("false"); continue;}
                if (st>en) {if (ll+1==rr) puts("true"); else puts("maybe"); continue;}
                int flag=Ask(1,st,en,rnum);
                if (!flag) puts("false");
                else if (flag==1)
                {
                    if (ll+1==st && rr-1==en) puts("true"); else puts("maybe");
                }
                else if (flag==2) puts("maybe");
                else puts("false");
            }
        }
    }
    return 0;
}

4373: 算术天才⑨与等差数列

在观摩了各种gcd做法后选择死亡

然后意外发现了一片净土

预处理区间和&平方和(需取模)&min 判断是否符合要求

感觉画风清奇

不被long long 搞死就可以了

(WA了四五发就是被long long搞死的TAT)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define lk k<<1
#define rk k<<1|1
const LL mod = 1000000009, SIX = 833333341; //SIX为6的逆元
const int NN = 300005,INF = 0x3f3f3f3f;
struct TR
{
	LL s1,s2,mn;
}tr[NN<<2];
int n,m,op,x,y,z,cnt=0;
LL a[NN];
bool flag;
LL ksm(LL xx,LL yy) 
{
	LL sum=1ll;
	for (xx%=mod;yy;xx=xx*xx%mod,yy>>=1) if (yy&1) sum=sum*xx%mod;
	return sum;
}
void push_up(int k)
{
	tr[k].s1 = tr[lk].s1 + tr[rk].s1;
	tr[k].s2 = (tr[lk].s2 + tr[rk].s2) % mod;
	tr[k].mn = min(tr[lk].mn,tr[rk].mn);
}

void Build(int k,int l,int r)
{
	if (l == r)
	{
		tr[k].s1 = tr[k].mn = a[l];
		tr[k].s2 = a[l] * a[l] % mod;
		return;
	}
	int mid = (l+r) >> 1;
	Build(lk,l,mid), Build(rk,mid+1,r);
	push_up(k);
}
void Change(int k,int l,int r,int p,LL v)
{
	if (l == r)
	{
		tr[k].s1 = tr[k].mn = v;
		tr[k].s2 = v*v % mod;
		return;
	}
	int mid = (l+r) >> 1;
	if (p <= mid) Change(lk,l,mid,p,v); else Change(rk,mid+1,r,p,v);
	push_up(k);
}

LL Query(int k,int l,int r,int L,int R,int t)
{
	if (L<=l && R>=r)
	{
		if (t == 1) return tr[k].s1; else return tr[k].s2;
	}
	int mid = (l+r) >> 1;
	LL pre = 0ll;
	if (L <= mid) pre += Query(lk,l,mid,L,R,t);
	if (R > mid) pre += Query(rk,mid+1,r,L,R,t);
	if (t == 2) pre %= mod;
	return pre;
}

LL Query_min(int k,int l,int r,int L,int R)
{
	if (L<=l && R>=r) return tr[k].mn;
	int mid = (l+r) >> 1;
	LL pre = INF;
	if (L <= mid) pre = min(pre,Query_min(lk,l,mid,L,R));
	if (R > mid) pre = min(pre,Query_min(rk,mid+1,r,L,R));
	return pre;
}

LL Get1(LL x,LL l,LL k)
{
	return x * l + (l - 1) * l / 2 * k;
}
LL Get2(LL x,LL l,LL k)
{
	LL ret = x * x % mod * l % mod;
	ret = (ret + (l - 1) * l % mod * k % mod * x % mod) % mod;
	ret += l * (l - 1) % mod * (2 * l - 1) % mod * k % mod * k % mod * SIX % mod;
	return ret % mod;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
	Build(1,1,n);
	while (m--)
	{
		scanf("%d",&op);
		if (op == 1) scanf("%d%d",&x,&y), x ^= cnt, y ^= cnt, Change(1,1,n,x,y);
		else
		{
			scanf("%d%d%d",&x,&y,&z), x ^= cnt, y ^= cnt, z ^= cnt;
			flag = 1;
			LL minn = Query_min(1,1,n,x,y);
			LL sum = Get1(minn,y-x+1,z);
			if (sum != Query(1,1,n,x,y,1)) flag = 0;
			if (flag && Get2(minn,y-x+1,z) != Query(1,1,n,x,y,2)) flag = 0;
			if (flag) puts("Yes"), ++cnt; else puts("No");
		}
	}
	return 0;
}

1858: [Scoi2010]序列操作

维护各种操作,强行上线段树即可。

部分说明如下:

$l0/l1$维护该区段从左边开始最长的连续$0/1$

$r0/r1$维护该区段从右边开始最长的连续$0/1$

$sum0/sum1$维护该区段中$0/1$的个数

$mx1/mx0$维护该区段中最长连续$0/1$的个数

$num=\{-1,0,1\}$分别表示该区段数字不同/全为0/全为1

$rev$为翻转标志

对这些值进行维护即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int read()
{
	int x=0; bool f=0; char ch;
	for (ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=1;
	for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; if (f) x=-x;
	return x;
}
const int NN = 100005;
int n,m;
struct TR
{
	int l,r,l0,r0,l1,r1,mx0,mx1,sum0,sum1,num,rev,c;
}tr[NN<<2];

void Rev(int k)
{
	swap(tr[k].l0,tr[k].l1), swap(tr[k].r0,tr[k].r1), swap(tr[k].mx0,tr[k].mx1), swap(tr[k].sum0,tr[k].sum1);
	if (tr[k].num != -1) tr[k].num ^= 1;
}
void Color(int k,int v)
{
	tr[k].rev = 0;
	int sum = tr[k].r - tr[k].l + 1;
	if (v == 0)
	{
		tr[k].sum0 = tr[k].l0 = tr[k].r0 = tr[k].mx0 = sum;
		tr[k].sum1 = tr[k].l1 = tr[k].r1 = tr[k].mx1 = 0;
	}
	else
	{
		tr[k].sum0 = tr[k].l0 = tr[k].r0 = tr[k].mx0 = 0;
		tr[k].sum1 = tr[k].l1 = tr[k].r1 = tr[k].mx1 = sum;
	}
	tr[k].num = v;
}
TR Merge(TR x,TR y)
{
	TR tmp;
	tmp.l = x.l, tmp.r = y.r;
	tmp.rev = 0, tmp.c = -1;
	tmp.l0 = x.l0, tmp.l1 = x.l1, tmp.r0 = y.r0, tmp.r1 = y.r1;
	tmp.mx0 = max(x.mx0,y.mx0), tmp.mx1 = max(x.mx1,y.mx1);
	tmp.mx0 = max(tmp.mx0,x.r0+y.l0), tmp.mx1 = max(tmp.mx1,x.r1+y.l1);
	tmp.sum0 = x.sum0 + y.sum0, tmp.sum1 = x.sum1 + y.sum1;
	if (x.num == 0) tmp.l0 = x.mx0 + y.l0;
		else if (x.num == 1) tmp.l1 = x.mx1 + y.l1;
	if (y.num == 0) tmp.r0 = y.mx0 + x.r0;
		else if (y.num == 1) tmp.r1 = y.mx1 + x.r1;
	if (x.num == y.num) tmp.num = x.num;
		else tmp.num = -1;
	return tmp;
}
void push_up(int k) { tr[k] = Merge(tr[k<<1],tr[k<<1|1]); }
void push_down(int k)
{
	if (tr[k].l == tr[k].r) return;
	if (tr[k].c != -1)
	{
		tr[k<<1].c = tr[k<<1|1].c = tr[k].c;
		Color(k<<1,tr[k].c), Color(k<<1|1,tr[k].c), tr[k].c = -1;
	}
	if (tr[k].rev)
	{
		tr[k<<1].rev ^= 1, tr[k<<1|1].rev ^= 1;
		Rev(k<<1), Rev(k<<1|1), tr[k].rev = 0;
	}
}
void Build(int k,int l,int r)
{
	tr[k].l = l, tr[k].r = r, tr[k].c = -1;
	if (l == r)
	{
		tr[k].num = read();
		if (tr[k].num) tr[k].l1 = tr[k].r1 = tr[k].mx1 = tr[k].sum1 = 1;
		else tr[k].l0 = tr[k].r0 = tr[k].mx0 = tr[k].sum0 = 1;
		return;
	}
	int mid = (l+r) >> 1;
	Build(k<<1,l,mid), Build(k<<1|1,mid+1,r);
	push_up(k);
}
void Change(int k,int x,int y,int v)
{
	push_down(k);
	int l=tr[k].l, r=tr[k].r;
	if (l == x && r == y) { Color(k,v), tr[k].c = v; return; }
	int mid = (l+r) >> 1;
	if (y <= mid) Change(k<<1,x,y,v);
	else if (x > mid) Change(k<<1|1,x,y,v);
	else Change(k<<1,x,mid,v), Change(k<<1|1,mid+1,y,v);
	push_up(k);
}
void Rever(int k,int x,int y)
{
	push_down(k);
	int l = tr[k].l, r = tr[k].r;
	if (l == x && r == y) { Rev(k), tr[k].rev = 1; return; }
	int mid = (l+r) >> 1;
	if (y <= mid) Rever(k<<1,x,y);
	else if (x > mid) Rever(k<<1|1,x,y);
	else Rever(k<<1,x,mid), Rever(k<<1|1,mid+1,y);
	push_up(k);
}
TR Query(int k,int x,int y)
{
	push_down(k);
	int l = tr[k].l, r = tr[k].r;
	if (l == x && r == y) return tr[k];
	int mid = (l+r) >> 1;
	if (y <= mid) return Query(k<<1,x,y);
	else if (x > mid) return Query(k<<1|1,x,y);
	else return Merge(Query(k<<1,x,mid),Query(k<<1|1,mid+1,y));
}
int Q_sum(int k,int x,int y)
{
	push_down(k);
	int l = tr[k].l, r = tr[k].r;
	if (l == x && y == r) return tr[k].sum1;
	int mid = (l+r) >> 1;
	if (y <= mid) return Q_sum(k<<1,x,y);
	else if (x > mid) return Q_sum(k<<1|1,x,y);
	else return Q_sum(k<<1,x,mid)+Q_sum(k<<1|1,mid+1,y);
}
int main()
{
	n = read(), m = read();
	Build(1,1,n);
	int x,y,op;
	for (int i=1;i<=m;++i)
	{
		op = read(), x = read()+1, y = read()+1;
		switch (op)
		{
			case 0: Change(1,x,y,0); break;
			case 1: Change(1,x,y,1); break;
			case 2: Rever(1,x,y); break;
			case 3: printf("%d\n",Q_sum(1,x,y)); break;
			case 4: printf("%d\n",Query(1,x,y).mx1); break;
		}
	}
	return 0;
}
Avatar_small
Bluehost Webmail Log 说:
2022年8月10日 13:01

Blue host Webmail lets the individual create their professional and personalized email address. Having a business or personal brand does require a personalized email address, which increases more credibility. The attraction from customers will be more when you use your business related or personal name in the mail instead of using @outlook or @gmail. Bluehost Webmail Login There are options under Blue host Webmail that allow users to create personal email without actually creating a website. The Blue host Webmail control panel allows you to create multiple emails with a user-friendly option to access the same.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter