Problem C: [noip2016十连测第三场]序列
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 78 Solved: 32
[ Submit][ Status][ Web Board]
Description
小A把自己之前得到的序列展示给了小B,不过这一次,他并不要求小B模仿他之前的行为。他给了小B一些询问,每个询问都是lrx的形式,要求小B数出在序列的第l个到第r个元素中有多少是不小于x的。小B很快就算出来了。小A很不甘心,于是要求动态修改这个序列……这样,他只要求每次修改后求出所有询问答案的和即可。然而小B还是很快就算出来了,小A很生气,于是把问题抛给了你。
Input
由于一些原因,本题采取一定的方式加密了修改操作。第一行三个整数nmq,分别表示序列长度、询问个数和修改
次数。第二行n个正整数描述序列。接下来m行每行三个数lrx,表示一次询问。最后q行每行两个数pv,表示把p^la
stans这个位置上的数修改成v^lastans(其中lastans指上次修改之后的答案,初始即为没有修改过的原序列的询
问答案,^为异或符号,C/C++中为^,pascal中为xor)。
【 数据范围与约定】
对于 20%的数据, n,m,q≤100
对于 40%的数据, n,m,q≤1000
对于 100%的数据, n,m,q≤100000, 序列中的数( 包括修改后的)
均为正数且不超过 n, 保证数据合法。
【 数据范围与约定】
对于 20%的数据, n,m,q≤100
对于 40%的数据, n,m,q≤1000
对于 100%的数据, n,m,q≤100000, 序列中的数( 包括修改后的)
均为正数且不超过 n, 保证数据合法。
Output
q+1行每行一个整数,第一行表示原序列的所有询问答案之和,后面q行表示每次修改之后的序列的所有询问答案之和。
Sample Input
4 2 2
1 4 2 3
2 4 3
1 3 2
6 6
2 7
Sample Output
4
3
4
HINT
【题解】【静态主席树+前缀和维护】
【NOIP考主席树。。。hehehe】
【先建一棵主席树,外层以每个位置为根的标号建树,内层权值线段树,首次询问时在[root[l] - root[r] ]里查询[x,n]】
【然后重新建树,外层以每次询问的x为根的标号建树,内层维护有多少个包含当前点的区间,前缀和维护,查询时,如果原数小于当前要更改为的元素,那么要加上中间这一段的答案;反之,要减去中间差的这一段的答案】
【NOIP考主席树。。。hehehe】
【先建一棵主席树,外层以每个位置为根的标号建树,内层权值线段树,首次询问时在[root[l] - root[r] ]里查询[x,n]】
【然后重新建树,外层以每次询问的x为根的标号建树,内层维护有多少个包含当前点的区间,前缀和维护,查询时,如果原数小于当前要更改为的元素,那么要加上中间这一段的答案;反之,要减去中间差的这一段的答案】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
struct node{
int Left,Right;
ll num;
}tree[5000010];
struct question{
int qL,qR,k;
}que[100010];
ll ans;
int a[100010],root[100010];
int n,m,q,sz;
int tmp(question a,question b)
{
return a.k<b.k;
}
void build(int &now,int l,int r,int x)
{
tree[++sz]=tree[now]; now=sz;
tree[now].num++;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) build(tree[now].Left,l,mid,x);
if(x>mid) build(tree[now].Right,mid+1,r,x);
}
ll ask(int x,int y,int l,int r,int al,int ar)
{
if(al<=l&&r<=ar) return tree[y].num-tree[x].num;
int mid=(l+r)>>1;
ll sum=0;
if(al<=mid) sum+=ask(tree[x].Left,tree[y].Left,l,mid,al,ar);
if(ar>mid) sum+=ask(tree[x].Right,tree[y].Right,mid+1,r,al,ar);
return sum;
}
void rebuild(int&now,int l,int r,int top,int al,int ar,int opt)
{
if(!opt||now<top) tree[++sz]=tree[now],now=sz;
if(al<=l&&r<=ar) {tree[now].num++; return;}
int mid=(l+r)>>1;
if(al<=mid) rebuild(tree[now].Left,l,mid,top,al,ar,opt);
if(ar>mid) rebuild(tree[now].Right,mid+1,r,top,al,ar,opt);
}
ll query(int x,int y,int l,int r,int val)
{
if(l==r) return tree[y].num-tree[x].num;
int mid=(l+r)>>1;
ll sum=tree[y].num-tree[x].num;
if(val<=mid) sum+=query(tree[x].Left,tree[y].Left,l,mid,val);
if(val>mid) sum+=query(tree[x].Right,tree[y].Right,mid+1,r,val);
return sum;
}
int main()
{
freopen("int.txt","r",stdin);
freopen("my.txt","w",stdout);
int i,j;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;++i)
{
scanf("%d",&a[i]);
root[i]=root[i-1];
build(root[i],1,n,a[i]);
}
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&que[i].qL,&que[i].qR,&que[i].k);
ans+=ask(root[que[i].qL-1],root[que[i].qR],1,n,que[i].k,n);
}
printf("%lld\n",ans);
sort(que+1,que+m+1,tmp);
memset(tree,0,sizeof(tree));
int t=1; sz=0;
for(i=1;i<=n;++i)
{
root[i]=root[i-1];
j=t;
if(que[t].k!=i) continue;
rebuild(root[i],1,n,0,que[t].qL,que[t].qR,0);
while(j<=m&&que[t].k==que[j].k) ++j;
for(int l=t+1;l<j;++l) rebuild(root[i],1,n,root[i],que[l].qL,que[l].qR,1);
if(j>m) break; t=j;
}
for(i=que[m].k+1;i<=n;++i) root[i]=root[i-1];
for(i=1;i<=q;++i)
{
ll site,val;
scanf("%lld%lld",&site,&val);
site^=ans; val^=ans;
if(a[site]<val) ans+=query(root[a[site]],root[val],1,n,site);
if(a[site]>val) ans-=query(root[val],root[a[site]],1,n,site);
a[site]=val;
printf("%lld\n",ans);
}
return 0;
}