值域線段樹 (玲瓏OJ 1117)
阿新 • • 發佈:2019-02-12
題目意思很簡單:
1、插入x
2、把小於x的數變成x
3、把大於x的數變成x
4、求集合中第x小數
5、求集合中小於x的數個數
思路: 線段樹,節點是值的分數,你可以離散,也可以不離散,直接標記;我的寫法是: 看程式碼註釋>>>
據說陣列改為指標會快點;程式碼比較挫.存一個;
#include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <iostream> using namespace std; typedef long long int LL; const LL INF=1000000000; const int maxn=6e6+100; struct ACM { struct segment { int val,lson,rson; bool mark; } seg[maxn]; int sz; /*** 開闢新的節點並初始化 */ int newnode() { sz++; if(sz>=maxn) { int lzq=5,zhangpan=0; lzq=lzq/zhangpan; } seg[sz].lson=seg[sz].rson=-1; seg[sz].val=0,seg[sz].mark=false; return sz; } /*** 初始化根節點 */ void init(int& root) { sz=-1; root=newnode(); } /*** 標記下放操作,如果沒有節點開闢新的節點; */ void pushdown(int i) { int l=seg[i].lson,r=seg[i].rson; if(l==-1) seg[i].lson=newnode(); if(r==-1) seg[i].rson=newnode(); if(seg[i].mark) { seg[i].mark=false; seg[l].mark=seg[r].mark=true; seg[l].val=seg[r].val=0; } } void pushup(int i) { int l=seg[i].lson,r=seg[i].rson; seg[i].val=seg[l].val+seg[r].val; } /*** 插入函式 ; 在 pos 位置上面加上 val; */ void ins(int i,int l,int r,int pos,int val) { if(l==r) { seg[i].val+=val; return ; } pushdown(i); int mid=(l+r)>>1; if(pos<=mid) ins(seg[i].lson,l,mid,pos,val); else ins(seg[i].rson,mid+1,r,pos,val); pushup(i); } /*** 將 L,R 這段區間上的值,更新為 0; */ void del(int i,int l,int r,int L,int R) { if(l==L&&r==R) { seg[i].val=0; seg[i].mark=true; return ; } pushdown(i); int mid=(l+r)>>1; if(R<=mid) del(seg[i].lson,l,mid,L,R); else if(L>mid) del(seg[i].rson,mid+1,r,L,R); else del(seg[i].lson,l,mid,L,mid),del(seg[i].rson,mid+1,r,mid+1,R); pushup(i); } int find(int i,int l,int r,int x) //第x小的數字; { if(l==r) return l; pushdown(i); int lval=0; int mid=(l+r)>>1; if(seg[i].lson!=-1) lval=seg[seg[i].lson].val; if(x<=lval) return find(seg[i].lson,l,mid,x); else return find(seg[i].rson,mid+1,r,x-lval); } int query(int i,int l,int r,int L,int R) //區間 數的個數; { if(l==L&&r==R) return seg[i].val; pushdown(i); int mid=(l+r)>>1; if(R<=mid) return query(seg[i].lson,l,mid,L,R); else if(L>mid) return query(seg[i].rson,mid+1,r,L,R); else return query(seg[i].lson,l,mid,L,mid)+query(seg[i].rson,mid+1,r,mid+1,R); } } AC; int main() { int m; scanf("%d",&m); int op,x,root,temp; AC.init(root); while(m--) { scanf("%d%d",&op,&x); switch(op) { case 1: AC.ins(root,0,INF,x,1); break; case 2: temp=AC.query(root,0,INF,0,x); AC.del(root,0,INF,0,x); AC.ins(root,0,INF,x,temp); break; case 3: temp=AC.query(root,0,INF,x,INF); AC.del(root,0,INF,x,INF); AC.ins(root,0,INF,x,temp); break; case 4: printf("%d\n",AC.find(root,0,INF,x)); break; case 5: printf("%d\n",AC.query(root,0,INF,0,x-1)); break; } } return 0; }
程式碼二:
#include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <iostream> using namespace std; const int INF=1000000000; const int maxn=6e6+100; struct ACM { /*** 對於 2,3 操作,先查詢個數,再插入這個數字: 意思就是更新到底部,加上查詢出來的個數; 並加上清零的標記; */ struct Node { int val,lson,rson; bool mark; } seg[maxn]; int sz; int newnode() { sz++; seg[sz].val=0; seg[sz].lson=-1; seg[sz].rson=-1; seg[sz].mark=false; return sz; } void init(int& root) { sz=-1; root=newnode(); } void pushdown(int i) { int l=seg[i].lson,r=seg[i].rson; if(l==-1) seg[i].lson=newnode(); if(r==-1) seg[i].rson=newnode(); if(seg[i].mark) { seg[i].mark=false; seg[l].mark=seg[r].mark=true; seg[l].val=seg[r].val=0; } } void pushup(int i) { int l=seg[i].lson,r=seg[i].rson; seg[i].val=seg[l].val+seg[r].val; } int query(int i,int l,int r,int L,int R) //區間 數的個數; { if(l==L&&r==R) return seg[i].val; pushdown(i); int mid=(l+r)>>1; if(R<=mid) return query(seg[i].lson,l,mid,L,R); else if(L>mid) return query(seg[i].rson,mid+1,r,L,R); else return query(seg[i].lson,l,mid,L,mid)+query(seg[i].rson,mid+1,r,mid+1,R); } void ins(int i,int l,int r,int pos,int val) { if(l==r) { seg[i].val+=val; return ; } pushdown(i); int mid=(l+r)>>1; if(pos<=mid) ins(seg[i].lson,l,mid,pos,val); else ins(seg[i].rson,mid+1,r,pos,val); pushup(i); } void operator2(int i,int l,int r,int x,int val) { if(l==r) { seg[i].val=val; return ; } int mid=(l+r)>>1; pushdown(i); if(x<=mid) operator2(seg[i].lson ,l,mid,x,val); else { seg[seg[i].lson].mark=true; seg[seg[i].lson].val=0;//如果,存在加到某一邊,不存在也需要開新的節點!! operator2(seg[i].rson,mid+1,r,x,val); } pushup(i); } void operator3(int i,int l,int r,int x,int val) { if(l==r) { seg[i].val=val; return ; } pushdown(i); int mid=(l+r)>>1; if(x<=mid) { seg[seg[i].rson].mark=true; seg[seg[i].rson].val=0; operator3(seg[i].lson,l,mid,x,val); } else operator3(seg[i].rson,mid+1,r,x,val); pushup(i); } int operator4(int i,int l,int r,int x) { if(l==r) return l; int mid=(l+r)>>1; pushdown(i); int val=seg[seg[i].lson].val; if(x<=val) return operator4(seg[i].lson,l,mid,x); else return operator4(seg[i].rson,mid+1,r,x-val); } } AC; int main() { int m; while(scanf("%d",&m)!=EOF) { int op,x,root,temp; AC.init(root); while(m--) { scanf("%d%d",&op,&x); switch(op) { case 1: AC.ins(root,0,INF,x,1); break; case 2: temp=AC.query(root,0,INF,0,x); AC.operator2(root,0,INF,x,temp); break; case 3: temp=AC.query(root,0,INF,x,INF); AC.operator3(root,0,INF,x,temp); break; case 4: printf("%d\n",AC.operator4(root,0,INF,x)); break; case 5: printf("%d\n",AC.query(root,0,INF,0,x-1)); break; } } } return 0; }