您的位置:首页 > 其它

【JZOJ5295】【清华集训模拟】Create(主席树)

2017-08-23 21:57 330 查看

Description



Solution

这题的40分非常的好打,直接倒着主席树一下就好了。

其实100分也差不多,只是要发现一些东西。

因为估价函数们是不会变化的,所以我们可以考虑用一个数据结构。

我们对于每个数a,只有大于估价函数的x才是有贡献的,我们可以考虑排序一下x,然后对于每个a找到最大的x小于等于a,然后统计这些区间有多少个覆盖a这个位置,这个可以用主席树来搞。

但是我们对于一段相同的颜色,我们都是可以被相同集合的估价函数来贡献的,所以我们可以考虑把相同颜色端的缩成一个颜色,然后区间询问。(主席树插进来的时候是区间修改)

我们每次修改一段颜色,我们可以暴力合并,这里用线段树或set统计一下就好了。最坏的情况就是一开始两两颜色不相同,然后每隔一个合并一次……最坏合并log次,每次分裂最多两次,最坏2*m次。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=4e5+7;
typedef long long ll;
int i,j,k,n,m,q,mid,num,kk;
ll ans,l,r,x;
struct node{
int l,r,bz;
ll sum;
}t[maxn*40];
struct nod{
int l,r,x;
}b[maxn];
bool cmp(nod x,nod y){return x.x<y.x;}
int a[maxn],root[maxn];
int c[maxn][3],tot,tt[maxn*4];
void insert(int &x,int y,int l,int r,int z,int o){
if(!x||x==y)x=++num,t[x]=t[y];
if(l==z&&r==o){t[x].sum+=r-l+1;t[x].bz++;return;}
int mid=(l+r)/2;
if(o<=mid)insert(t[x].l,t[y].l,l,mid,z,o);
else if(z>mid)insert(t[x].r,t[y].r,mid+1,r,z,o);
else insert(t[x].l,t[y].l,l,mid,z,mid),insert(t[x].r,t[y].r,mid+1,r,mid+1,o);
t[x].sum=t[x].bz*(r-l+1)+t[t[x].l].sum+t[t[x].r].sum;
}
ll find(int x,int l,int r,int z,int o){
if(!x)return 0;
if(l==z&&r==o)return t[x].sum;
int mid=(l+r)/2;
if(o<=mid)return find(t[x].l,l,mid,z,o)+(ll)(o-z+1)*t[x].bz;
else if(z>mid)return find(t[x].r,mid+1,r,z,o)+(ll)(o-z+1)*t[x].bz;
else return find(t[x].l,l,mid,z,mid)+find(t[x].r,mid+1,r,mid+1,o)+(ll)(o-z+1)*t[x].bz;
}
int zhao(int x){
int l=1,r=m,mid;
while(l<r){
mid=(l+r+1)/2;
if(b[mid].x<=x)l=mid;else r=mid-1;
}
if(b[l].x>x)l--;
return l;
}
void down(int x){
if(tt[x]){
tt[x*2]=tt[x],tt[x*2+1]=tt[x];
tt[x]=0;
}
}
void change(int x,int l,int r,int y,int z,int o){
if(l==y&&r==z){tt[x]=o;return;}
down(x);
int mid=(l+r)/2;
if(z<=mid)change(x*2,l,mid,y,z,o);
else if(y>mid)change(x*2+1,mid+1,r,y,z,o);
else change(x*2,l,mid,y,mid,o),change(x*2+1,mid+1,r,mid+1,z,o);
}
int find1(int x,int l,int r,int y){
if(l==r)return tt[x];
int mid=(l+r)/2;
down(x);
if(y<=mid)return find1(x*2,l,mid,y);
else return find1(x*2+1,mid+1,r,y);
}
int main(){
freopen("create.in","r",stdin);
freopen("create.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
fo(i,1,n)scanf("%d",&a[i]);a[n+1]=a
+1;
fo(i,1,n+1){
if(a[i]!=a[i-1]){
if(i>1){
c[++tot][0]=j,c[tot][1]=i-1,c[tot][2]=a[i-1];
change(1,1,n,j,i-1,tot);
}
j=i;
if(i==n+1)continue;
}
}
fo(i,1,m)scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].x);
sort(b+1,b+1+m,cmp);
fo(i,1,m)
insert(root[i],root[i-1],1,n,b[i].l,b[i].r);
fo(i,1,tot){
j=zhao(c[i][2]);
ans+=find(root[j],1,n,c[i][0],c[i][1]);
}
printf("%lld\n",ans);
while(q--){
scanf("%lld%lld%lld",&l,&r,&x);l^=ans,r^=ans,x^=ans;
k=find1(1,1,n,l);while(l<=n&&c[k][2]==x)l=c[k][1]+1,k=find1(1,1,n,l);
k=find1(1,1,n,r);while(r&&c[k][2]==x)r=c[k][0]-1,k=find1(1,1,n,r);
if(l>r){printf("%lld\n",ans);continue;}c[++tot][0]=l,c[tot][1]=r,c[tot][2]=x;kk=tot;
j=zhao(x);
ans+=find(root[j],1,n,l,r);k=find1(1,1,n,l);
if(l!=c[k][0]){
k=find1(1,1,n,l-1);
c[++tot][0]=c[k][0],c[tot][1]=l-1,c[tot][2]=c[k][2];
change(1,1,n,c[tot][0],c[tot][1],tot);
}
k=find1(1,1,n,l);
while(l<=r&&c[k][1]<=r){
j=zhao(c[k][2]);ans-=find(root[j],1,n,l,c[k][1]);
change(1,1,n,l,c[k][1],kk);
j=c[k][1];c[k][1]=l-1;
l=j+1;
k=find1(1,1,n,l);
}
if(l<=r){
j=zhao(c[k][2]);ans-=find(root[j],1,n,l,r);change(1,1,n,l,r,kk);
c[k][0]=r+1;
}
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: