首页 > 其他分享 >[Ynoi2003] 铃原露露

[Ynoi2003] 铃原露露

时间:2024-02-21 18:57:39浏览次数:22  
标签:tmin 露露 Ynoi2003 pb int 铃原 mp ans sei

$\text{前言}$ :

本篇题解是我对其他题解的理解和梳理。

$\text{题意}$ :

    
   给你一棵树,和一个 $n$ 的排列 $a$。定义一个满足要对的点对 $(L,R)$ 为:对于 $\forall x,y$ 如果满足 $a_x,a_y \in [L,R]$,则 $a_{Lca(x,y)} \in [L,R]$。  
   $q$ 次询问形如 $l,r$,求:$[l,r]$ 中满足要求的点对数量。  
   数据规模:$n ,q \le 2\times 10 ^5$
   

$\text{分析}$ :


我们知道,$Lca$ 满足相关性质我们常用点分治或者 `dsu on tree`,与距离相关常用点分治,这题我们尝试使用 `dsu on tree` 做。

令 $Lca(x,y) = z$,我们考虑一个合法的区间满足 $a_x < a_z < a_y$。我们考虑什么样的区间不满足要求。

不妨设 $a_x < a_y$,有:
1. 如果 $a_z < a_x$,则 $l \in (a_z,a_x], \ r \ge a_y$ 的区间不满足要求。
2. 如果 $a_z > a_y$,则 $l \in [1,a_x], \ r \in [a_y,a_z)$ 的区间不满足要求。

但是枚举这样的点对是 $O(n^2)$ 的。观察发现,对于同一个 $z$,不合法点对 $(x,y)$,$(d,e)$ 如果都不满足限制 $1$,如果 $[x,y] \subset [d,e]$,显然 $[x,y]$ 可以约束到更多的点,那么另一个点对就可以删去。$2$ 同理。

这样我们就可以在 `dsu on tree` 中对于每个点 $x$ 找 $a_x$ 的前驱后继,这样我们可以找出大概 $2 \times n \log n$ 个点对。

发现我们大概要求一个矩形内符合要求的点,
我们把询问离线下来,用扫描线做。枚举每个右端点,累计左端点可能的个数。大概来说就是求历史最小值 $0$ 的个数和,这是满足区间可减性的,即可以差分。如果不满足的话,我们通常可以分治求解,不过要多带一只 $\log$。复杂度 $O (n \log^2 n) $。




------------

 $\text{Add} \ \ 1.20.2024$


我当时写这篇题解的时候还没有敲代码,后来我自己写的时候发现维护历史 $0$ 的个数之和并不是很好做,就顺便提一嘴。  

首先我们要求历史 $0$ 的个数和,也就是各个版本 $0$ 的个数之和。因此我们考虑维护**当前最小值**,**当前最小值个数**,**历史 $0$ 个数之和**。

首先有一个想法是在 $\operatorname{push\ up}$ 的时候记录时间差来维护一段时间的贡献,但是这样不好处理 $\operatorname{push\ down}$。

之后我 $\text{Search Online}$,但是没找到。然后参考其他了题解,发现了一个很聪明(可能是套路)的做法:记一个 $\operatorname{tag_2}$ 把时间差累积起来算贡献。即在扫描线每次移动 $r$ 的时候都在整棵树为 $0$ 的区间打上一个 $\operatorname{tag_2}$。但是我不太会分析这个的复杂度,等我再研究一下。

还有个小细节,我们打 $\operatorname{tag_2}$ 的时候可以只在从 $1$ 到当前枚举的右端点 $r$ 的区间打标记,这样我们不用查询两次做差分,少一半的查询。

因为我写完了,给出参考代码。
  1 #include<bits/stdc++.h>
  2 
  3 #define pb emplace_back
  4 #define pi pair<int,int>
  5 #define mp make_pair
  6 #define fi first
  7 #define se second
  8 const int N=2e5+50;
  9 typedef long long ll;
 10 using namespace std;
 11 
 12 int n,m;
 13 int a[N],sei[N], so[N];
 14 vector<int>e[N];
 15 set<int>sg[N];
 16 vector<pi> Re[N];
 17 bool cmp(int a,int b){return sg[sei[a]].size() > sg[sei[b]].size();}
 18 void dsu(int u){
 19   int sot=0;
 20   for(auto v : e[u]) dsu(v);
 21   for(auto v : e[u]) so[++sot] = v;
 22   if(!sot) {sg[sei[u]].insert(a[u]);return;}
 23   sort(so+1,so+sot+1,cmp);
 24   int fu = so[1];
 25   for(int i=2;i<=sot;++i){
 26     int nv = so[i];
 27     for(auto v : sg[sei[nv]]){
 28       auto ql = sg[sei[fu]].lower_bound(v);
 29       if(ql!=sg[sei[fu]].end()){
 30         int x = v, y = *ql, z = a[u];
 31         if(x > y) swap(x, y);
 32         if(z < x) {Re[y].pb(mp(z + 1, x));}
 33         if(z > y) {Re[y].pb(mp(1, x));Re[z].pb(mp(-1, x));}
 34       }
 35       if(ql!=sg[sei[fu]].begin()) {
 36         ql--;
 37         int x = v, y = *ql, z = a[u];
 38         if(x > y) swap(x, y);
 39         if(z < x) {Re[y].pb(mp(z + 1, x));}
 40         if(z > y) {Re[y].pb(mp(1, x));Re[z].pb(mp(-1, x));}
 41       }
 42     }
 43     for(auto v : sg[sei[nv]]) sg[sei[fu]].insert(v);
 44   }
 45   sei[u]=sei[fu];
 46   sg[sei[fu]].insert(a[u]);
 47 }
 48 
 49 struct node{
 50   ll tsm, nsm;
 51   int tmin;
 52   node operator+(const node b) const {
 53     if(!nsm && !tsm) return b;
 54     if(!b.nsm && !b.tsm) return *this;
 55     node ans;
 56     ans.tsm = tsm + b.tsm;
 57     ans.tmin = min(tmin, b.tmin);
 58     ans.nsm = nsm * (tmin == ans.tmin) + b.nsm * (ans.tmin == b.tmin);
 59     return ans;
 60   }
 61 };
 62 
 63 struct segment{
 64   #define lc k << 1
 65   #define rc k << 1 | 1
 66   #define lcon lc,l,mid
 67   #define rcon rc,mid+1,r
 68   #define Mid int mid=l+r>>1
 69   node tm[N << 2];
 70   int tag1[N << 2], tag2[N << 2];
 71   void pu(int k){
 72     tm[k] = tm[lc] + tm[rc];
 73   }
 74   void ad1(int k,int v){
 75     tag1[k] += v;
 76     tm[k].tmin += v;
 77   }
 78   void ad2(int k,int v){
 79     tag2[k] += v;
 80     tm[k].tsm += (ll)tm[k].nsm * v;
 81   }
 82   void build(int k,int l,int r){
 83     tm[k].nsm = r - l + 1;
 84     if(l==r)return; Mid;
 85     build(lcon), build(rcon); pu(k);
 86   }
 87   void pd(int k){
 88     if(tag1[k]){
 89       ad1(lc,tag1[k]);
 90       ad1(rc,tag1[k]);
 91     }
 92     if(tag2[k]){
 93       if(tm[lc].tmin == tm[k].tmin) ad2(lc,tag2[k]);
 94       if(tm[rc].tmin == tm[k].tmin) ad2(rc,tag2[k]);
 95     }
 96     tag1[k]=tag2[k]=0;
 97   }
 98   void mo(int k,int l,int r,int x,int y,int v){
 99     if(x>y)return;if(x<=l&&r<=y) return ad1(k,v);
100     Mid; pd(k); if(x<=mid) mo(lcon,x,y,v);
101     if(y>mid) mo(rcon,x,y,v); pu(k);
102   }
103   void update(int k,int l,int r,int x,int y,int v){
104     if(x>y||tm[k].tmin>0)return;
105     if(x<=l&&r<=y) return ad2(k,v);
106     Mid; pd(k); if(x<=mid) update(lcon,x,y,v);
107     if(y>mid) update(rcon,x,y,v); pu(k);
108   }
109   ll qr(int k,int l,int r,int x,int y){
110     if(x<=l&&r<=y)return tm[k].tsm;
111     Mid; pd(k); ll ans = 0;
112     if(x<=mid) ans+=qr(lcon,x,y);
113     if(y>mid) ans+=qr(rcon,x,y);
114     return ans;
115   }
116 }ti;
117 
118 vector<pi>rq[N];
119 ll ans[N];
120 
121 int main(){
122   ios::sync_with_stdio(false);
123   cin>>n>>m;
124   for(int i=1;i<=n;++i)cin>>a[i];
125   for(int i=2,x;i<=n;++i)cin>>x,e[x].pb(i);
126   for(int i=1;i<=n;++i)sei[i]=i;
127   dsu(1); ti.build(1,1,n);
128   for(int i=1;i<=m;++i){
129     int l,r; cin >> l >> r;
130     rq[r].pb(mp(l,i));
131   }
132   for(int i=1;i<=n;++i){
133     for(auto [l, r] : Re[i]) {
134       if(l > 0) ti.mo(1,1,n,l,r,1);
135       else ti.mo(1,1,n,-l,r,-1);
136     }
137     ti.update(1,1,n,1,i,1);
138     for(auto [l, id] : rq[i]) {
139       ans[id] = ti.qr(1, 1, n, l, i);
140     }
141   }
142   for(int i=1;i<=m;++i) cout << ans[i] << "\n";
143   return 0;
144 }

 

















标签:tmin,露露,Ynoi2003,pb,int,铃原,mp,ans,sei
From: https://www.cnblogs.com/Saka-Noa/p/18025997

相关文章

  • P8528 [Ynoi2003] 铃原露露
    一道很好的启发式合并题目。思路考虑一个事实。我们想要求出对于每个点对不合法的情况。例如现在考虑到了\((x,y)\),它们的\(\text{lca}\)为\(z\)。有几种情况:\(a_x<a_z<a_y\),那么是合法的。\(a_x<a_y<a_z\),那么包含\(a_x,a_y\)不包含\(a_z\)的区间是不合法的,......
  • 「题解」洛谷 P8529 [Ynoi2003] 赫露艾斯塔
    构造半平面莫队?/jk注意到对于一个半平面的直线,通过平移和旋转经过的点数,一定大于等于它们的对称差,因为对称差中的点会被经过奇数次,不在对称差中的点会被经过偶数次。那么......