caioj1442:第k小的數Ⅱ
阿新 • • 發佈:2017-10-23
space center scanf mes blank owb tdi 操作 node
【傳送門:caioj1442】
簡要題意:
給出n個點,每個點都有一個權值,m個操作,操作有兩種:第一種是詢問l到r的第k小的值,然後輸出這個值,第二種是將第x個點的值改為k
題解:
又是一道主席樹的例題,不過簡直比前兩題(caioj1441,caioj1443)難不止一點點
看到第一種操作,我們可以用主席樹來搞,但是第二種操作的話,我們就要用樹狀數組來維護每個第二種操作所帶來的影響,而且每次要求第一種操作的時候都要先在樹狀數組中找到相應的點,然後再處理主席樹
參考代碼:
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; int a[210000]; struct node { int lc,rc,c; }tr[3100000];int cnt; int rt[210000];int n; int ust[210000];//樹狀數組 int lowbit(int x)//樹狀數組用來找上司或下屬 { return x&-x; } void Link(int &u,int l,int r,int p,int c) {if(u==0) u=++cnt; tr[u].c+=c; if(l==r) return ; int mid=(l+r)/2; if(p<=mid) Link(tr[u].lc,l,mid,p,c); else Link(tr[u].rc,mid+1,r,p,c); } void Merge(int &u1,int u2) { if(u1==0){u1=u2;return ;} if(u2==0) return ; tr[u1].c+=tr[u2].c; Merge(tr[u1].lc,tr[u2].lc); Merge(tr[u1].rc,tr[u2].rc); }void Turn(int u,int c)//樹狀數組的實時更新 //c==-1時樹狀數組記錄每個點所在線段樹的根 //c==0時記錄左孩子 //c==1時記錄右孩子 { while(u>=n+1) { if(c==-1) ust[u]=rt[u]; else if(c==0) ust[u]=tr[ust[u]].lc; else if(c==1) ust[u]=tr[ust[u]].rc; u-=lowbit(u); } } void Modefy(int u,int p,int c)//對於修改值就用樹狀數組來節約時間 { while(u<=2*n) { Link(rt[u],0,1000000000,p,c); u+=lowbit(u); } } int Getsum(int u)//求出修改過後樹狀數組得到的值 { int ret=0; while(u>=n+1) { ret+=tr[tr[ust[u]].lc].c; u-=lowbit(u); } return ret; } int Ask(int u1,int u2,int p1,int p2,int l,int r,int p) { if(l==r) return l; int c=tr[tr[u2].lc].c-tr[tr[u1].lc].c+Getsum(p2+n)-Getsum(p1+n); int mid=(l+r)/2; if(p<=c) { Turn(p1+n,0); Turn(p2+n,0); return Ask(tr[u1].lc,tr[u2].lc,p1,p2,l,mid,p); } else { Turn(p1+n,1); Turn(p2+n,1); return Ask(tr[u1].rc,tr[u2].rc,p1,p2,mid+1,r,p-c); } } int main() { int m; scanf("%d%d",&n,&m); cnt=0;memset(rt,0,sizeof(rt)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); Link(rt[i],0,1000000000,a[i],1); Merge(rt[i],rt[i-1]); } char st[2]; for(int i=1;i<=m;i++) { scanf("%s",st+1); if(st[1]==‘Q‘) { int l,r,k; scanf("%d%d%d",&l,&r,&k); Turn(l+n-1,-1); Turn(r+n,-1); printf("%d\n",Ask(rt[l-1],rt[r],l-1,r,0,1000000000,k)); } else { int p,c; scanf("%d%d",&p,&c); Modefy(p+n,a[p],-1); a[p]=c; Modefy(p+n,a[p],1); } } return 0; }
caioj1442:第k小的數Ⅱ