1. 程式人生 > >魔法少女 LJJ——線段樹

魔法少女 LJJ——線段樹

namespace 機器 struct spa 轉動 查詢 isp ble merge

題目

【題目描述】

在森林中見過會動的樹,在沙漠中見過會動的仙人掌過後,魔法少女 LJJ 已經覺得自己見過世界上的所有稀奇古怪的事情了。

LJJ 感嘆道“這裏真是個迷人的綠色世界,空氣清新、淡雅,到處散發著醉人的奶漿味;小猴在枝頭悠來蕩去,好不自在;各式各樣的鮮花爭相開放,各種樹枝的枝頭掛滿沈甸甸的野果;鳥兒的歌聲婉轉動聽,小河裏飄著落下的花瓣真是人間仙境”。

SHY 覺得 LJJ 還是太 naive,一天, SHY 帶著自己心愛的圖找到 LJJ,對 LJJ 說:“既然你已經見識過動態樹,動態仙人掌了,那麽今天就來見識一下動態圖吧”。

LJJ:“要支持什麽操作?”

SHY:
1. 新建一個節點,權值為 $x$。
2. 連接兩個節點。
3. 將一個節點 $a$ 所屬於的聯通快內權值小於 $x$ 的所有節點權值變成 $x$。
4. 將一個節點 $a$ 所屬於的聯通快內權值大於 $x$ 的所有節點權值變成 $x$。
5. 詢問一個節點 $a$ 所屬於的聯通塊內的第 $k$ 小的權值是多少。
6. 詢問一個節點 $a$ 所屬聯通快內所有節點權值之積與另一個節點 $b$ 所屬聯通快內所有節點權值之積的大小。
7. 詢問 $a$ 所在聯通塊內節點的數量
8. 若兩個節點 $a$,$b$ 直接相連,將這條邊斷開。
9. 若節點 $a$ 存在,將這個點刪去。

LJJ:“我可以離線嗎?”

SHY:“可以,每次操作是不加密的。”
LJJ:“我可以暴力嗎?”
SHY:“自重。”

LJJ很郁悶,你能幫幫他嗎?


【輸入格式】

第一行一個整數 $n$ ,代表島嶼數量。

接下來 $n-1$ 行,每行三個整數 $u,v,w$ ,代表 $u$ 號島嶼和 $v$ 號島嶼由一條代價為 $c$ 的橋梁直接相連,保證 $1 \le u,v \le n$ 且 $1 \le c \le 100000 $ 。

第 $n+1$ 行,一個整數 $m$ ,代表敵方機器能使用的次數。

接下來 $m$ 行,每行一個整數 $k_i$ ,代表第 $i$ 次後,有 $k_i$ 個島嶼資源豐富,接下來 $k$ 個整數$h_1,h_2,…h_k$ ,表示資源豐富島嶼的編號。


【輸出格式】
具體輸出格式見樣例 。
【樣例輸入】

12
1 2
1 3
1 4
1 5
1 6
2 1 2
2 2 3
2 3 4
2 4 5
9 1
3 2 5
5 3 4


【樣例輸出】

6


【數據範圍與提示】
對 $100\%$ 的數據 $0\le m \le 400000,c \le 7$,所有出現的數均 $\le 1000000000$,所有出現的點保證存在.

題解

題目中 $ c \leq 7 $,即說明僅有前 $ 7 $ 個操作

對於操作一,新建一棵線段樹,並插入這個點的值

對於操作二,合並兩顆線段樹,用並查集維護

對於操作三,查詢個數並刪除小於 $ x $ 的點,插入 $ x $

對於操作四,類似三

對於操作五,線段樹上二分即可

對於操作六,可以發現 $ \log(a\times b)=\log a+\log b $,所以轉化成 $ log x $ 比較和即可

對於操作七,查詢整個線段樹點的個數即可

於是這又是一道大力題

代碼

技術分享圖片
  1 #include<bits/stdc++.h>
  2 #define LL long long
  3 #define db double
  4 #define _(d) while(d(isdigit(ch=getchar())))
  5 using namespace std;
  6 int R(){
  7     int x;bool f=1;char ch;_(!)if(ch==-)f=0;x=ch^48;
  8     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
  9 const int N=2e6+5;
 10 int n,m,tmp,cnt,fa[N],d[N],rot[N];
 11 struct node{int op,x,y;}q[N];
 12 struct seg{int ls,rs,num;bool tag;db val;}tr[N*20];
 13 int ef(int x){return lower_bound(d+1,d+1+n,x)-d;}
 14 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
 15 #define Ls(x) tr[x].ls
 16 #define Rs(x) tr[x].rs
 17 void pushup(int rt){
 18     tr[rt].num=tr[Ls(rt)].num+tr[Rs(rt)].num;
 19     tr[rt].val=tr[Ls(rt)].val+tr[Rs(rt)].val;
 20     return;
 21 }
 22 void pushdown(int rt){
 23     tr[rt].tag=0;
 24     tr[Ls(rt)].num=tr[Ls(rt)].val=0,tr[Ls(rt)].tag=1;
 25     tr[Rs(rt)].num=tr[Rs(rt)].val=0,tr[Rs(rt)].tag=1;
 26     return;
 27 }
 28 void insert(int &rt,int l,int r,int k,int x,db y){
 29     if(!rt)rt=++cnt;
 30     if(l==r){tr[rt].num+=x,tr[rt].val+=y;return;}
 31     int mid=(l+r)>>1;
 32     if(tr[rt].tag)pushdown(rt);
 33     if(k<=mid)insert(Ls(rt),l,mid,k,x,y);
 34     else insert(Rs(rt),mid+1,r,k,x,y);
 35     pushup(rt);
 36     return;
 37 }
 38 void merge(int &o1,int o2,int l,int r){
 39     if(!o1||!o2){o1+=o2;return;}
 40     if(l==r){
 41         tr[o1].num+=tr[o2].num,tr[o1].val+=tr[o2].val;
 42         return;
 43     }
 44     int mid=(l+r)>>1;
 45     if(tr[o1].tag)pushdown(o1);
 46     if(tr[o2].tag)pushdown(o2);
 47     merge(Ls(o1),Ls(o2),l,mid),merge(Rs(o1),Rs(o2),mid+1,r);
 48     pushup(o1);
 49     return;
 50 }
 51 int query(int rt,int l,int r,int ql,int qr){
 52     if(!rt||qr<ql)return 0;
 53     if(ql<=l&&qr>=r)return tr[rt].num;
 54     int mid=(l+r)>>1,res=0;
 55     if(tr[rt].tag)pushdown(rt);
 56     if(ql<=mid)res=query(Ls(rt),l,mid,ql,qr);
 57     if(qr>mid)res+=query(Rs(rt),mid+1,r,ql,qr);
 58     return res;
 59 }
 60 void clean(int rt,int l,int r,int ql,int qr){
 61     if(!rt||qr<ql)return;
 62     if(ql<=l&&qr>=r){
 63         tr[rt].num=tr[rt].val=0,tr[rt].tag=1;
 64         return;
 65     }
 66     int mid=(l+r)>>1;
 67     if(ql<=mid)clean(Ls(rt),l,mid,ql,qr);
 68     if(qr>mid)clean(Rs(rt),mid+1,r,ql,qr);
 69     pushup(rt);
 70     return;
 71 }
 72 int ask(int rt,int l,int r,int k){
 73     if(l==r)return d[l];
 74     int mid=(l+r)>>1;
 75     if(tr[rt].tag)pushdown(rt);
 76     if(k<=tr[Ls(rt)].num)return ask(Ls(rt),l,mid,k);
 77     else return ask(Rs(rt),mid+1,r,k-tr[Ls(rt)].num);
 78 }
 79 int main(){
 80     m=R();
 81     for(int i=1;i<=m;i++){
 82         int op=R(),x=R(),y=0;
 83         if(op!=1&&op!=7)y=R();
 84         q[i]=(node){op,x,y};
 85         if(op==3||op==4)d[++n]=y;
 86         if(op==1)d[++n]=x;
 87     }
 88     sort(d+1,d+1+n);
 89     n=unique(d+1,d+1+n)-d-1;
 90     for(int i=1;i<=m;i++){
 91         int op=q[i].op,x=q[i].x,y=q[i].y;
 92         if(op==1)insert(rot[++tmp],1,n,ef(x),1,(db)log(x)),fa[tmp]=tmp;
 93         if(op==2){
 94             int fx=find(x),fy=find(y);
 95             if(fx!=fy)fa[fy]=fx,merge(rot[fx],rot[fy],1,n);
 96         }
 97         if(op==3){
 98             int fx=find(x),k=ef(y),sum=query(rot[fx],1,n,1,k-1);
 99             clean(rot[fx],1,n,1,k-1),insert(rot[fx],1,n,k,sum,sum*log(y));
100         }
101         if(op==4){
102             int fx=find(x),k=ef(y),sum=query(rot[fx],1,n,k+1,n);
103             clean(rot[fx],1,n,k+1,n),insert(rot[fx],1,n,k,sum,sum*log(y));
104         }
105         if(op==5)printf("%d\n",ask(rot[find(x)],1,n,y));
106         if(op==6)puts(tr[rot[find(x)]].val>tr[rot[find(y)]].val?"1":"0");
107         if(op==7)printf("%d\n",tr[rot[find(x)]].num);
108     }
109     return 0;
110 }
View Code

魔法少女 LJJ——線段樹