Transformation HDU - 4578線段樹綜合操作

我不是手機發表於2020-11-13

這天,狄大人是有名的名偵探,他也很會判案,他常常會問元芳:”元芳,你怎麼看?“:
現在有n個犯人等待被審判,每個犯人都有一個罪惡值, a1, a2, …, an. 這些犯人的罪惡之最開始都是0, 但是經過狄大人的審判,n個犯人的罪惡值會有不同程度的改變,偷偷告訴你,因為狄大人斷案能力很強,所以他每一次判案都是直接審批一個連續區間[l,r]的犯人哦。狄大人有三個審判方式。
第一種審判 1: 這種審判的犯人一般是一些小案件的犯人,狄大人會讓受審判的犯人的罪惡值增加c。
第二種審判 2: 這種犯人一般都是一些 大案件的犯人,狄大人會讓受審判的犯人的罪惡值增加 (c-1)*a,其中a是犯人原來的罪惡值。
第三種審判 3:這種犯人犯的錯都是法律種明確規定的,狄大人會讓受審判的犯人的罪惡值都變為c。 狄大人在審判犯人之後,會好奇犯人的罪惡值都是多少,因此他會詢問一個區間的犯人的罪惡值。
詢問 4: 因為只是罪惡值無法表現出犯人的罪惡程度,因此狄大人想要知道相對罪惡值bk=akp的值,現在狄大人想要知道一些犯人的相對罪惡值。
但是狄大人實在太忙了,因此他又去問了元芳:”元芳,你怎麼看?“,元芳表示:”我坐著看“,元芳也不知道犯人的相對罪惡值,因此就需要聰明又機智的你來幫助狄大人找到犯人的相對罪惡值啦。
Input
輸入有多組資料,資料不超過10組。
對於每一組資料,對於每一組資料,第一行輸入兩個數,n 和 m。表示有n個犯人,狄大人會進行m次審判。1 <= n, m <= 100,000.
接下來輸入m行,每一行都包含一次審判的資訊,每一行輸入一個數 op,表示狄大人的行為. op=1,2,3:表示狄大人將要審判犯人,接下來輸入三個數,x y c,表示狄大人審判的犯人的範圍在[x,y]之間,並且審判的依據是c。 op=4:表示狄大人想要知道犯人的相對罪惡值,接下來輸入三個數,x y p,其中x y表示狄大人想要知道的犯人的範圍在[x,y]之間,並且相對罪惡值bk=akp。(1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
輸入 0 0時終止輸入。
Output
對於狄大人的每次詢問,即op=4,在一行種輸出詢問區間的所有相對罪惡值之和。答案可能很大,你只需要計算答案除以10007的餘數。
Sample Input
7 7
1 5 6 4
4 5 6 1
1 1 5 2
2 3 4 6
3 3 4 6
1 3 6 3
4 1 6 2
0 0
Sample Output
8
300
Hint
樣例中,狄大人需要審判n個犯人,m次行為,最開始,所有犯人的罪惡值都為0, 第一次行為之後:每個犯人的罪惡值為:0 0 0 0 4 4 0 第二次行為之後:bk=ak1。所以對於該詢問,ans=b4+b5=8. 第三次行為之後:每個犯人的罪惡值為:2 2 2 2 6 4 0 第四次行為之後:每個犯人的罪惡值為:2 2 12 12 6 4 0 第五次行為之後:每個犯人的罪惡值為:2 2 6 6 6 4 0 第六次行為之後:每個犯人的罪惡值為:2 2 9 9 9 7 0 第七次行為之後:bk=ak2。所以對於該詢問,ans=b1+b2+b3+b4+b5+b6=300.

按題目要求來一步步做,總共有區間加法、乘法、替換、區間求和。

#include<map>
#include<stack>
#include<queue>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
//#include<bits/stdc++.h>
using namespace std;
const int mod=10007;
const int maxn=1e5+5;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
bool tag[maxn*4];
int tree[maxn*4];
void down(int k)
{
	tag[ls]=tag[k];
	tag[rs]=tag[k];
	tree[ls]=tree[k];
	tree[rs]=tree[k];
	tag[k]=0;
}
void uphold(int k)
{
	if(!tag[ls]||!tag[rs])
		tag[k]=0;
	else if(tree[ls]!=tree[rs])
		tag[k]=0;
	else
	{
		tag[k]=1;
		tree[k]=tree[ls]=tree[rs];
	}
}
void update1(int l,int r,int l1,int r1,int v,int k)
{
	if(tag[k]&&l1<=l&&r1>=r)
	{
		tree[k]=(tree[k]+v)%mod;
		return ;
	}
	if(tag[k])
		down(k);
	if(l1<=mid)
		update1(l,mid,l1,r1,v,ls);
	if(r1>mid)
		update1(mid+1,r,l1,r1,v,rs);
	uphold(k);
}
void update2(int l,int r,int l1,int r1,int v,int k)
{
	if(tag[k]&&l1<=l&&r1>=r)
	{
		tree[k]=(tree[k]*v)%mod;
		return ;
	}
	if(tag[k])
		down(k);
	if(l1<=mid)
		update2(l,mid,l1,r1,v,ls);
	if(r1>mid)
		update2(mid+1,r,l1,r1,v,rs);
	uphold(k);
}
void update3(int l,int r,int l1,int r1,int v,int k)
{
	if(tag[k]&&l1<=l&&r1>=r)
	{
		tree[k]=v;
		return ;
	}
	if(tag[k])
		down(k);
	if(l1<=mid)
		update3(l,mid,l1,r1,v,ls);
	if(r1>mid)
		update3(mid+1,r,l1,r1,v,rs);
	uphold(k);
}
int query(int l,int r,int l1,int r1,int v,int k)
{
	//cout<<l<<" "<<r<<" "<<l1<<" "<<r1<<" "<<v<<" "<<k<<endl;
	if(tag[k]&&l1<=l&&r1>=r)
	{
		int ans=1;
		for(int i=1;i<=v;i++)
			ans=(ans*tree[k])%mod;
		ans=(ans*(r-l+1))%mod;
		return ans;
	}
	if(tag[k])
		down(k);
	int ans=0;
	if(l1<=mid)
		ans+=query(l,mid,l1,r1,v,ls);
	if(r1>mid)
		ans+=query(mid+1,r,l1,r1,v,rs);
	return ans;
}
int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)&&n+m)
	{
		memset(tag,1,sizeof(tag));
		while(m--)
		{
			int s,x,y,v;
			scanf("%d%d%d%d",&s,&x,&y,&v);
			if(s==1)
				update1(1,n,x,y,v,1);
			else if(s==2)
				update2(1,n,x,y,v,1);
			else if(s==3)
				update3(1,n,x,y,v,1);
			else
				printf("%d\n",query(1,n,x,y,v,1)%mod);
		}
	}
    return 0;
}

相關文章