1. 程式人生 > >JZOJ-senior-5943. 【NOIP2018模擬11.01】樹

JZOJ-senior-5943. 【NOIP2018模擬11.01】樹

Time Limits: 1000 ms Memory Limits: 262144 KB

Description

在這裡插入圖片描述

Input

第一行一個整數 n 表示序列長度, 接下來一行 n 個整數描述這個序列.
第三行一個整數 q 表示操作次數, 接下來 q 行每行一次操作, 格式同題目描述.

Output

輸出等同於操作 2, 3 次數之和的行數, 每行一個非負整數表示對應詢問的答案. 注意操作 2 的答案不需要進行取模.

Sample Input

Sample Input1
5
8 4 3 5 6
5
2 3 5
3 1 2
1 2 4 3
2 3 5
3 1 2

樣例 2
見下發檔案中的 ex_seg2.in/out.

Sample Output

Sample Output1
14
608
10
384

樣例 1 解釋
第三次操作後, 序列變為 [8, 0, 3, 1, 6].

Data Constraint

對於前 30% 的資料, n, q ≤ 100;
對於另 20% 的資料, 沒有操作 1;
對於另 20% 的資料, 沒有操作 3;
對於 100% 的資料, n, q ≤ 10^5, ai ≤ 10^9, k ≤ 2^30, 1 ≤ l ≤ r ≤ n.

Solution

每次修改只會讓數變小,一個數最多隻會被修改 l

o g log
我們用線段樹維護一個區間是否有修改的必要(用區間的或值來判斷),需要修改就暴力修改
對於操作三,把式子展開,再維護一個區間平方和就行了
時間複雜度 O ( n l
o g 2 n ) O(nlog^2n)

Code

#include<algorithm>
#include<cstdio>
#include<cctype>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
#define L x<<1
#define R L|1

using namespace std;

const int N=1e5+5,P=998244353;
int n,m,t,opl,opr,k,a[N];
struct node{ll s1; int s2,p;}tr[4*N];

inline void read(int &n)
{
	int x=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	n=w?-x:x;
}

void update(int x)
{
	tr[x].s1=tr[L].s1+tr[R].s1;
	tr[x].s2=(tr[L].s2+tr[R].s2)%P;
	tr[x].p=tr[L].p|tr[R].p;
}

void build(int x,int l,int r)
{
	if(l==r)
	{
		tr[x].s1=a[l];
		tr[x].s2=(ll)a[l]*(ll)a[l]%P;
		tr[x].p=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(L,l,mid),build(R,mid+1,r);
	update(x);
}

void modify(int x,int st,int en,int l,int r)
{
	if(st==en)
	{
		tr[x].s1&=k;
		tr[x].s2=(ll)tr[x].s1*(ll)tr[x].s1%P;
		tr[x].p=tr[x].s1;
		return;
	}
	int mid=(st+en)>>1;
	if(r<=mid)
	{
		if((tr[L].p&k)<tr[L].p) modify(L,st,mid,l,r);
	}
	else if(l>mid)
	{
		if((tr[R].p&k)<tr[R].p) modify(R,mid+1,en,l,r);
	}
	else
	{
		if((tr[L].p&k)<tr[L].p) modify(L,st,mid,l,mid);
		if((tr[R].p&k)<tr[R].p) modify(R,mid+1,en,mid+1,r);
	}
	update(x);
}

node ask(int x,int st,int en,int l,int r)
{
	if(st==l&&en==r) return tr[x];
	int mid=(st+en)>>1;
	if(r<=mid) return ask(L,st,mid,l,r);
	else if(l>mid) return ask(R,mid+1,en,l,r);
	else
	{
		node b1=ask(L,st,mid,l,mid);
		node b2=ask(R,mid+1,en,mid+1,r);
		return (node){b1.s1+b2.s1,(b1.s2+b2.s2)%P,0};
	}
}

int main()
{
	freopen("seg.in","r",stdin);
	freopen("seg.out","w",stdout);
	read(n);
	fo(i,1,n) read(a[i]);
	build(1,1,n);
	read(m);
	fo(i,1,m)
	{
		read(t),read(opl),read(opr);
		if(t==1)
		{
			read(k);
			modify(1,1,n,opl,opr);
			continue;
		}
		node e=ask(1,1,n,opl,opr);
		ll ans=0;
		if(t==2) ans=e.s1;
		else
		{
			e.s1%=P,e.s2%=P;
			ans=((ll)2*(ll)(opr-opl+1)%P*(ll)e.s2%P+(ll)2*(ll)e.s1%P*(ll)e.s1%P)%P;
		}
		printf("%lld\n",ans);
	}
}