题意:给出数组A[1,2,...,n]和m条指令,每条指令形如(L,R,v,p)表示统计出A[L]...A[R]中严格小于v的有多少个,然后把A[p]修改成uk/(R-L+1)
思路:首先是分块,将数组分成sqrt(n)快,对每一块排序,询问的时候,对于两头的块,直接暴力,中间的,因为排好序了,所以直接二分就可以了,修改操作,用类似于插入排序的方法维护
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=4096;
const int maxm=300010;
int N,M,U;
int L,R,v,p;
int size;
int A[maxm];
int block[maxn][maxn];
int num;
void init()
{
size=int(sqrt(N));
for(int i=0;i<N;i++)scanf("%d",&A[i]);
num=0;
int j=0;
for(int i=0;i<N;i++)
{
block[num][j]=A[i];
if(++j==size){num++,j=0;}
}
for(int i=0;i<num;i++)sort(block[i],block[i]+size);
if(j)sort(block[num],block[num]+j);
}
int Query(int l,int r,int v)
{
int ans=0;
int xpos=l/size,ypos=r/size;
if(xpos==ypos)
{
for(int i=l;i<=r;i++)
if(A[i]<v)ans++;
}
else
{
for(int i=l;i<(xpos+1)*size;i++)if(A[i]<v)ans++;
for(int i=ypos*size;i<=r;i++)if(A[i]<v)ans++;
for(int i=xpos+1;i<ypos;i++)
ans+=lower_bound(block[i],block[i]+size,v)-block[i];
}
return ans;
}
void Change(int p,int x)
{
if(A[p]==x)return;
int bpos=p/size;
int pos=0;
int old=A[p];
A[p]=x;
while(block[bpos][pos]<old)pos++;
block[bpos][pos]=x;
if(x<=old)
while(pos>0&&block[bpos][pos]<block[bpos][pos-1])
swap(block[bpos][pos],block[bpos][pos-1]),pos--;
else
while(pos<size-1&&block[bpos][pos]>block[bpos][pos+1])
swap(block[bpos][pos],block[bpos][pos+1]),pos++;
}
int main()
{
while(scanf("%d%d%d",&N,&M,&U)!=EOF)
{
init();
while(M--)
{
scanf("%d%d%d%d",&L,&R,&v,&p);
L--,R--,p--;
int k=Query(L,R,v);
Change(p,(LL)U*k/(R-L+1));
}
for(int i=0;i<N;i++)printf("%d\n",A[i]);
}
return 0;
}
树套树TLE了,空间开太大。。。
#include<bits/stdc++.h>
using namespace std;
const int maxn=300010;
int A[maxn];
int N,M,U;
int L,R,v,p;
int tot;
struct Node
{
int ch[2];
int r;//优先级
int v;//值
int s;
int cnt;//自身重复次数
void init(int val){v=val;ch[0]=ch[1]=0;s=cnt=1;r=rand();}
int cmp(int x)const
{
if(x==v)return -1;
return x<v?0:1;
}
}tree[maxn*15];
void maintain(int x)
{
tree[x].s=tree[x].cnt;
tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s;
}
void rotate(int &o,int d)
{
int k=tree[o].ch[d^1];
tree[o].ch[d^1]=tree[k].ch[d];
tree[k].ch[d]=o;
maintain(o);
maintain(k);
o=k;
}
void insert(int &o,int x)
{
if(!o)
{
o=++tot;
tree[o].init(x);
}
else
{
if(x==tree[o].v)tree[o].cnt++;
else
{
int d=(x<tree[o].v?0:1);
insert(tree[o].ch[d],x);
if(tree[tree[o].ch[d]].r>tree[o].r)
rotate(o,d^1);
}
}
maintain(o);
}
void remove(int &o,int x)
{
if(!o)return;
int d=tree[o].cmp(x);
if(d==-1)
{
int u=o;
if(tree[o].cnt>1)tree[o].cnt--;
else if(tree[o].ch[0]&&tree[o].ch[1])
{
int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0);
rotate(o,d2);
remove(tree[o].ch[d2],x);
}
else
{
if(!tree[o].ch[0])o=tree[o].ch[1];
else o=tree[o].ch[0];
tree[u]=tree[0];
}
}
else remove(tree[o].ch[d],x);
if(o)maintain(o);
}
//返回最大值
int get_max(int o)
{
while(tree[o].ch[0])o=tree[o].ch[0];
return tree[o].v;
}
//返回最小值
int get_min(int o)
{
while(tree[o].ch[1])o=tree[o].ch[1];
return tree[o].v;
}
//返回val的前驱,如果没有的话返回y
//y的初值可赋成0,表示没有前驱
int get_pred(int o,int val,int y)
{
if(!o)return y;
if(tree[o].v<=val)//注意大于等于号
return get_pred(tree[o].ch[1],val,tree[o].v);
else return get_pred(tree[o].ch[0],val,y);
}
//返回val的后继,如果没有的话返回y
//y的初值可赋成0,表示没有后继
int get_succ(int o,int val,int y)
{
if(!o)return y;
if(tree[o].v>=val)return get_succ(tree[o].ch[0],val,tree[o].v);
else return get_succ(tree[o].ch[1],val,y);
}
//返回第k大的元素的值
int get_kth(int o,int k)
{
if(!o)return 0;
if(k<=tree[tree[o].ch[0]].s)return get_kth(tree[o].ch[0],k);
else if(k>tree[tree[o].ch[0]].s+tree[o].cnt)
return get_kth(tree[o].ch[1],k-tree[tree[o].ch[0]].s-tree[o].cnt);
return tree[o].v;
}
//返回val的排名
int get_rank(int o,int val)
{
if(!o)return 0;
int lsize=tree[tree[o].ch[0]].s;
if(val<tree[o].v)
return get_rank(tree[o].ch[0],val);
else if(val>tree[o].v)
return get_rank(tree[o].ch[1],val)+lsize+tree[o].cnt;
return lsize;
}
struct IntervalTree
{
int root[maxn<<2];
void build(int o,int l,int r)
{
for(int i=l;i<=r;i++)
insert(root[o],A[i]);
if(l==r)return ;
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
}
void update(int o,int l,int r,int pos,int val)
{
remove(root[o],A[pos]);
insert(root[o],val);
if(l==r)return ;
int mid=(l+r)>>1;
if(pos<=mid)update(o<<1,l,mid,pos,val);
else update(o<<1|1,mid+1,r,pos,val);
}
int query(int o,int l,int r,int q1,int q2,int val)
{
if(l>r)return 0;
if(q1<=l&&r<=q2)return get_rank(root[o],val);
int mid=(l+r)>>1;//cout<<mid<<endl;
int ans=0;
if(q1<=mid)ans+=query(o<<1,l,mid,q1,q2,val);
if(q2>mid)ans+=query(o<<1|1,mid+1,r,q1,q2,val);
return ans;
}
}tr;
void init()
{
tot=0;
memset(tr.root,0,sizeof(tr.root));
}
int main()
{
while(scanf("%d%d%d",&N,&M,&U)!=EOF)
{
for(int i=1;i<=N;i++)scanf("%d",&A[i]);
init();
tr.build(1,1,N);
while(M--)
{
scanf("%d%d%d%d",&L,&R,&v,&p);
int ans=tr.query(1,1,N,L,R,v);
//printf("%d\n",ans);
tr.update(1,1,N,p,(long long)U*ans/(R-L+1));
A[p]=v;
}
for(int i=1;i<=N;i++)printf("%d\n",A[i]);
}
return 0;
}