1 A - Super Mario
这道题要求某区间内比h小的个数,其实这里可以类似于树状数组求逆序数那样。关键是如何转换成树状数组的模型,这才是本题的难点。
我们首先分析,如果知道h在该区间的哪个位置,那么剩下的就很好做了。我们还可以发现,如果找到了当前的比h小的所有点(大于的点我们先忽略掉),那么我们就可以用树状数组求它的[l,r]区间的和。这样就跟树状数组有了一点联系,但是还不够,因为我们发现,h的大小会影响我们所要找的区间。什么意思呢?就是我们先找到的是h1,再找h2,但h1>h2,就会出现这样的问题:h1所对应的区间找到了,但再找h2时,它对应的区间中可能会有比h2大的数,这样就不符合条件了。所以说这里有一个离线算法,就是先把所有的询问存下来,再按照h的大小进行从小到大排序,然后根据h的大小,从小到大地一个个插入所有区间内的数,这样就符合条件了。
  
   - 
    
     
    
    
     
      #include<iostream>
     
    
- 
    
     
    
    
     
      #include<cstdio>
     
    
- 
    
     
    
    
     
      #include<cstring>
     
    
- 
    
     
    
    
     
      #include<algorithm>
     
    
- 
    
     
    
    
     
      using 
      namespace std;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      const 
      int maxn = 
      1e5+
      5;
     
    
- 
    
     
    
    
     
      struct 
      Query
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      int l,r,h;
     
    
- 
    
     
    
    
     	
      int id;
     
    
- 
    
     
    
    
     	
      bool 
      operator < (Query a)
     
    
- 
    
     
    
    
     
      	{
     
    
- 
    
     
    
    
     		
      return h < a.h;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     
      }q[maxn];
     
    
- 
    
     
    
    
     
      struct 
      Node
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      int num;
     
    
- 
    
     
    
    
     	
      int id;
     
    
- 
    
     
    
    
     	
      bool 
      operator < (Node a)
     
    
- 
    
     
    
    
     
      	{
     
    
- 
    
     
    
    
     		
      return num < a.num;
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     
      }a[maxn];
     
    
- 
    
     
    
    
     
      int n,m;
     
    
- 
    
     
    
    
     
      int tree[maxn<<
      2],ans[maxn];
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int lowbit(int x)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      return x & (-x);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      void update(int x,int d)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      for(
      int i = x; i <= n; i += 
      lowbit(i))
     
    
- 
    
     
    
    
     
      		tree[i] += d;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int getsum(int x)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      int sum = 
      0;
     
    
- 
    
     
    
    
     	
      for(
      int i = x; i > 
      0; i -= 
      lowbit(i))
     
    
- 
    
     
    
    
     
      		sum += tree[i];
     
    
- 
    
     
    
    
     	
      return sum;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int main()
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     	
      int t,cas = 
      1;
     
    
- 
    
     
    
    
     
      	cin >> t;
     
    
- 
    
     
    
    
     	
      while(t--)
     
    
- 
    
     
    
    
     
      	{
     
    
- 
    
     
    
    
     
      		cin >> n >> m;
     
    
- 
    
     
    
    
     		
      for(
      int i = 
      1; i <= n; i++)
     
    
- 
    
     
    
    
     
      		{
     
    
- 
    
     
    
    
     
      			cin >> a[i].num;
     
    
- 
    
     
    
    
     
      			a[i].id = i;
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      for(
      int i = 
      1; i <= m; i++)
     
    
- 
    
     
    
    
     
      		{
     
    
- 
    
     
    
    
     
      			cin >> q[i].l >> q[i].r >> q[i].h;
     
    
- 
    
     
    
    
     
      			q[i].l++, q[i].r++;
     
    
- 
    
     
    
    
     
      			q[i].id = i;
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      sort(a+
      1,a+
      1+n);
     
    
- 
    
     
    
    
     		
      sort(q+
      1,q+
      1+m);
     
    
- 
    
     
    
    
     		
      memset(tree,
      0,
      sizeof(tree));
     
    
- 
    
     
    
    
     		
      int idx = 
      1;
     
    
- 
    
     
    
    
     		
      for(
      int i = 
      1; i <= m; i++)
     
    
- 
    
     
    
    
     
      		{
     
    
- 
    
     
    
    
     			
      while(q[i].h >= a[idx].num && idx <= n)
     
    
- 
    
     
    
    
     
      			{
     
    
- 
    
     
    
    
     				
      update(a[idx].id,
      1);
     
    
- 
    
     
    
    
     
      				idx++;
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      			ans[q[i].id] = 
      getsum(q[i].r) - 
      getsum(q[i].l
      -1);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      printf(
      "Case %d:\n",cas++);
     
    
- 
    
     
    
    
     		
      for(
      int i = 
      1; i <= m; i++)
     
    
- 
    
     
    
    
     			
      printf(
      "%d\n",ans[i]);
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
     	
      return 
      0;
     
    
- 
    
     
    
    
     
      }
     
    
 2 B - Sequence II
枚举C点,那么[1 , c-1]区间内,满足i<j&&a[i]<a[j] 的个数设为x; [c,n]区间内比c大的个数设为用;根据乘法原理,x*y就是所要的,那么枚举所有的C点,累加所有的x*y;
  
   - 
    
     
    
    
     
      #include <iostream>
     
    
- 
    
     
    
    
     
      #include <stdio.h>
     
    
- 
    
     
    
    
     
      #include <string>
     
    
- 
    
     
    
    
     
      #include <string.h>
     
    
- 
    
     
    
    
     
      #include <algorithm>
     
    
- 
    
     
    
    
     
      const 
      int N=
      1e5+
      100;
     
    
- 
    
     
    
    
     
      using 
      namespace std;
     
    
- 
    
     
    
    
     
      typedef 
      long 
      long ll;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int c[N],n;  
      //树状数组
     
    
- 
    
     
    
    
     
      int f[N],g[N];
     
    
- 
    
     
    
    
     
      int a[N];
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int lowbit(int x)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
       
      return x&-x;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      void update(int x)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
      
      while(x<=n)
     
    
- 
    
     
    
    
     
       {
     
    
- 
    
     
    
    
     
         c[x]+=
      1;
     
    
- 
    
     
    
    
     
         x+=
      lowbit(x);
     
    
- 
    
     
    
    
     
       }
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int getsum(int x)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
      
      int ans=
      0;
     
    
- 
    
     
    
    
      
      while(x>
      0)
     
    
- 
    
     
    
    
     
       {
     
    
- 
    
     
    
    
     
         ans+=c[x];
     
    
- 
    
     
    
    
     
         x-=
      lowbit(x);
     
    
- 
    
     
    
    
     
       }
     
    
- 
    
     
    
    
      
      return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int main()
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
        
      int T;
     
    
- 
    
     
    
    
        
      scanf(
      "%d",&T);
     
    
- 
    
     
    
    
        
      while(T--)
     
    
- 
    
     
    
    
     
         {
     
    
- 
    
     
    
    
          
      scanf(
      "%d",&n);
     
    
- 
    
     
    
    
          
      for(
      int i=
      1;i<=n;i++)
      scanf(
      "%d",&a[i]);
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
          
      memset(c,
      0,
      sizeof(c));
     
    
- 
    
     
    
    
          
      for(
      int i=
      1;i<=n;i++)
     
    
- 
    
     
    
    
     
           {
     
    
- 
    
     
    
    
     
              f[i]=
      getsum(a[i]);
     
    
- 
    
     
    
    
             
      update(a[i]);
     
    
- 
    
     
    
    
     
           }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
          
      memset(c,
      0,
      sizeof(c));
     
    
- 
    
     
    
    
          
      for(
      int i=n;i>=
      1;i--)
     
    
- 
    
     
    
    
     
           {
     
    
- 
    
     
    
    
            
      update(a[i]);
     
    
- 
    
     
    
    
     
             g[i]=n-i+
      1-
      getsum(a[i]);
     
    
- 
    
     
    
    
     
           }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
           ll ans=
      0,sum=
      0;
     
    
- 
    
     
    
    
          
      for(
      int i=
      1;i<=n;i++)
     
    
- 
    
     
    
    
     
           {
     
    
- 
    
     
    
    
     
             ans+=sum*g[i];
     
    
- 
    
     
    
    
     
             sum+=f[i];
     
    
- 
    
     
    
    
     
           }
     
    
- 
    
     
    
    
          
      printf(
      "%I64d\n",ans);
     
    
- 
    
     
    
    
     
         }
     
    
- 
    
     
    
    
        
      return 
      0;
     
    
- 
    
     
    
    
     
      }
     
    
 3 C - To the moon
涉及历史查询,一眼主席树的题目,关键的如何进行区间修改。
主席树与线段树不同之处就是 每一棵树是不能修改的,也就是不能够pushDown。那么能否一直新建节点?答案是不可以,如果用新建节点来替代pushDown操作,那么每一次都会一直新建到叶子节点,空间肯定是撑不住的。
主席树区间修一个很巧妙的方法:更新的时候和普通线段树一样,pushup 时由于没有pushDown 子树是不会更新的,所以用自己的 lazy 更新就可以了.也就是 sum[i] = sum[lson[i]] + sum[rson[i]] + lazy[i] * (r - l + 1)。查询的时候,将每一个节点的 lazy 值放在函数参数上带着,解决了pushDown的问题。
  
   - 
    
     
    
    
     
      #include<bits/stdc++.h>
     
    
- 
    
     
    
    
     
      #define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
     
    
- 
    
     
    
    
     
      #define pii pair<int,int>
     
    
- 
    
     
    
    
     
      #define clr(a,b) memset((a),b,sizeof(a))
     
    
- 
    
     
    
    
     
      #define rep(i,a,b) for(int i = a;i < b;i ++)
     
    
- 
    
     
    
    
     
      #define pb push_back
     
    
- 
    
     
    
    
     
      #define MP make_pair
     
    
- 
    
     
    
    
     
      #define LL long long
     
    
- 
    
     
    
    
     
      #define ull unsigned LL
     
    
- 
    
     
    
    
     
      #define ls i << 1
     
    
- 
    
     
    
    
     
      #define rs (i << 1) + 1
     
    
- 
    
     
    
    
     
      #define fi first
     
    
- 
    
     
    
    
     
      #define se second
     
    
- 
    
     
    
    
     
      #define ptch putchar
     
    
- 
    
     
    
    
     
      #define CLR(a) while(!(a).empty()) a.pop()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      using 
      namespace std;
     
    
- 
    
     
    
    
     
      inline LL read() {
     
    
- 
    
     
    
    
     
          LL s = 
      0,w = 
      1;
     
    
- 
    
     
    
    
         
      char ch = 
      getchar();
     
    
- 
    
     
    
    
         
      while(!
      isdigit(ch)) {
     
    
- 
    
     
    
    
             
      if(ch == 
      '-') w = 
      -1;
     
    
- 
    
     
    
    
     
              ch = 
      getchar();
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      while(
      isdigit(ch))
     
    
- 
    
     
    
    
     
              s = s * 
      10 + ch - 
      '0',ch = 
      getchar();
     
    
- 
    
     
    
    
         
      return s * w;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      inline void write(LL x) {
     
    
- 
    
     
    
    
         
      if(x < 
      0)
     
    
- 
    
     
    
    
             
      putchar(
      '-'), x = -x;
     
    
- 
    
     
    
    
         
      if(x > 
      9)
     
    
- 
    
     
    
    
             
      write(x / 
      10);
     
    
- 
    
     
    
    
         
      putchar(x % 
      10 + 
      '0');
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      const 
      int maxn = 
      1e5 + 
      10;
     
    
- 
    
     
    
    
     
      const 
      int M = maxn * 
      40;
     
    
- 
    
     
    
    
     
      LL C[M],lazy[M];
     
    
- 
    
     
    
    
     
      int lson[M],rson[M];
     
    
- 
    
     
    
    
     
      int tot,T[maxn];
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      void build(int &i,int l,int r){
     
    
- 
    
     
    
    
     
          i = ++ tot;
     
    
- 
    
     
    
    
     
          C[i] = lazy[i] = 
      0;
     
    
- 
    
     
    
    
         
      if(l == r){
     
    
- 
    
     
    
    
     
              LL x = 
      read();
     
    
- 
    
     
    
    
     
              C[i] = x;
     
    
- 
    
     
    
    
             
      return ;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      int mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
         
      build(lson[i],l,mid);
     
    
- 
    
     
    
    
         
      build(rson[i],mid + 
      1,r);
     
    
- 
    
     
    
    
     
          C[i] = C[lson[i]] + C[rson[i]];
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      void update(int l,int r,int ul,int ur,int &i,int last,LL val){
     
    
- 
    
     
    
    
     
          C[++ tot] = C[last];
     
    
- 
    
     
    
    
     
          lson[tot] = lson[last];
     
    
- 
    
     
    
    
     
          rson[tot] = rson[last];
     
    
- 
    
     
    
    
     
          lazy[tot] = lazy[last];
     
    
- 
    
     
    
    
     
          i = tot;
     
    
- 
    
     
    
    
         
      if(ul <= l && r <= ur){
     
    
- 
    
     
    
    
     
              C[i] += (r - l + 
      1) * val;
     
    
- 
    
     
    
    
     
              lazy[i] += val;
     
    
- 
    
     
    
    
             
      return ;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      int mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
         
      if(ul <= mid) 
      update(l,mid,ul,ur,lson[i],lson[last],val);
     
    
- 
    
     
    
    
         
      if(ur > mid) 
      update(mid + 
      1,r,ul,ur,rson[i],rson[last],val);
     
    
- 
    
     
    
    
     
          C[i] = C[lson[i]] + C[rson[i]] + (r - l + 
      1) * lazy[i];
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      LL query(int l,int r,int ql,int qr,int i,LL add){
     
    
- 
    
     
    
    
         
      if(ql <= l && r <= qr){
     
    
- 
    
     
    
    
             
      return C[i] + add * (r - l + 
      1);
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      int mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
     
          LL ans = 
      0;
     
    
- 
    
     
    
    
         
      if(ql <= mid) ans += 
      query(l,mid,ql,qr,lson[i],add + lazy[i]);
     
    
- 
    
     
    
    
         
      if(qr > mid) ans += 
      query(mid + 
      1,r,ql,qr,rson[i],add + lazy[i]);
     
    
- 
    
     
    
    
         
      return ans;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int main() {
     
    
- 
    
     
    
    
         
      int n = 
      read(),m = 
      read();
     
    
- 
    
     
    
    
         
      build(T[
      0],
      1,n);
     
    
- 
    
     
    
    
         
      int now = 
      0;
     
    
- 
    
     
    
    
         
      while(m --){
     
    
- 
    
     
    
    
             
      char op; 
      scanf(
      " %c",&op);
     
    
- 
    
     
    
    
             
      if(op == 
      'C'){
     
    
- 
    
     
    
    
                 
      int l = 
      read(),r = 
      read(),d = 
      read();
     
    
- 
    
     
    
    
                 
      update(
      1,n,l,r,T[now + 
      1],T[now],d);
     
    
- 
    
     
    
    
     
                  ++ now;
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      else 
      if(op == 
      'Q'){
     
    
- 
    
     
    
    
                 
      int l = 
      read(),r = 
      read();
     
    
- 
    
     
    
    
                 
      write(
      query(
      1,n,l,r,T[now],lazy[now])); 
      ptch(
      '\n');
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      else 
      if(op == 
      'H'){
     
    
- 
    
     
    
    
                 
      int l = 
      read(),r = 
      read(),t = 
      read();
     
    
- 
    
     
    
    
                 
      write(
      query(
      1,n,l,r,T[t],lazy[t])); 
      ptch(
      '\n');
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      else {
     
    
- 
    
     
    
    
                 
      int t = 
      read();
     
    
- 
    
     
    
    
     
                  now = t;
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      return 
      0;
     
    
- 
    
     
    
    
     
      }
     
    
 4 D - 粟粟的书架
这题其实是分两个题来做
对于R > 1时,设计状态如下:
fi,j,k:从(1,1)到(i,j)的矩形里,大于等于k的数字的总和
gi,j,k:从(1,1)到(i,j)的矩形里,大于等于k的数字的个数
每次询问等价成4个矩形里的结果相加减,二分k,暴力算最小的那个数要多少个就行
对于R == 1时,建立一棵主席树就行了
  
   - 
    
     
    
    
     
      #include<iostream>
     
    
- 
    
     
    
    
     
      #include<cstdio>
     
    
- 
    
     
    
    
     
      #include<queue>
     
    
- 
    
     
    
    
     
      #include<vector>
     
    
- 
    
     
    
    
     
      #include<bitset>
     
    
- 
    
     
    
    
     
      #include<algorithm>
     
    
- 
    
     
    
    
     
      #include<cstring>
     
    
- 
    
     
    
    
     
      #include<map>
     
    
- 
    
     
    
    
     
      #include<stack>
     
    
- 
    
     
    
    
     
      #include<set>
     
    
- 
    
     
    
    
     
      #include<cmath>
     
    
- 
    
     
    
    
     
      #include<ext/pb_ds/priority_queue.hpp>
     
    
- 
    
     
    
    
     
      using 
      namespace std;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      const 
      int maxn = 
      5E5 + 
      50;
     
    
- 
    
     
    
    
     
      const 
      int T = 
      20;
     
    
- 
    
     
    
    
     
      const 
      int N = 
      202;
     
    
- 
    
     
    
    
     
      const 
      int M = 
      1010;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int R,C,q,cnt,f[N][N][M],g[N][N][M],root[maxn]
     
    
- 
    
     
    
    
     
          ,lc[maxn*T],rc[maxn*T],c[maxn*T],t[maxn*T];
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      bool Judge(int r1,int c1,int r2,int c2,int k,int h)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      return f[r2][c2][k] - f[r1
      -1][c2][k] - f[r2][c1
      -1][k] + f[r1
      -1][c1
      -1][k] >= h;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      void Print(int r1,int c1,int r2,int c2,int k,int h)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      int z = k + 
      1;
     
    
- 
    
     
    
    
         
      int ans = g[r2][c2][z] - g[r1
      -1][c2][z] - g[r2][c1
      -1][z] + g[r1
      -1][c1
      -1][z];
     
    
- 
    
     
    
    
         
      int res = f[r2][c2][z] - f[r1
      -1][c2][z] - f[r2][c1
      -1][z] + f[r1
      -1][c1
      -1][z];
     
    
- 
    
     
    
    
     
          res = h - res;
     
    
- 
    
     
    
    
         
      int Add = res / k;
     
    
- 
    
     
    
    
         
      if (res % k != 
      0) ++Add;
     
    
- 
    
     
    
    
         
      printf(
      "%d\n",ans + Add);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int Insert(int o,int l,int r,int k)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      int ret = ++cnt;
     
    
- 
    
     
    
    
     
          c[ret] = c[o] + k;
     
    
- 
    
     
    
    
     
          t[ret] = t[o] + 
      1;
     
    
- 
    
     
    
    
         
      if (l == r) 
      return ret;
     
    
- 
    
     
    
    
         
      int mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
         
      if (k <= mid) rc[ret] = rc[o],lc[ret] = 
      Insert(lc[o],l,mid,k);
     
    
- 
    
     
    
    
         
      else lc[ret] = lc[o],rc[ret] = 
      Insert(rc[o],mid+
      1,r,k);
     
    
- 
    
     
    
    
         
      return ret;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int Query(int o1,int o2,int l,int r,int h)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      int tot = c[o2] - c[o1];
     
    
- 
    
     
    
    
         
      if (tot < h) 
      return 
      -1;
     
    
- 
    
     
    
    
         
      if (l == r) {
     
    
- 
    
     
    
    
             
      int ret = h / l;
     
    
- 
    
     
    
    
             
      if (h % l != 
      0) ++ret;
     
    
- 
    
     
    
    
             
      return ret;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      int ret,res,mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
     
          res = c[rc[o2]] - c[rc[o1]];
     
    
- 
    
     
    
    
         
      if (res >= h) 
      return 
      Query(rc[o1],rc[o2],mid+
      1,r,h);
     
    
- 
    
     
    
    
     
          ret = t[rc[o2]] - t[rc[o1]];
     
    
- 
    
     
    
    
         
      return ret + 
      Query(lc[o1],lc[o2],l,mid,h - res);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int getint()
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      char ch = 
      getchar();
     
    
- 
    
     
    
    
         
      int ret = 
      0;
     
    
- 
    
     
    
    
         
      while (ch < 
      '0' || 
      '9' < ch) ch = 
      getchar();
     
    
- 
    
     
    
    
         
      while (
      '0' <= ch && ch <= 
      '9')
     
    
- 
    
     
    
    
     
              ret = ret*
      10 + ch - 
      '0',ch = 
      getchar();
     
    
- 
    
     
    
    
         
      return ret;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      int main()
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
         
      #ifdef DMC
     
    
- 
    
     
    
    
             
      freopen(
      "DMC.txt",
      "r",stdin);
     
    
- 
    
     
    
    
         
      #endif
     
    
- 
    
     
    
    
          
     
    
- 
    
     
    
    
     
          R = 
      getint();
     
    
- 
    
     
    
    
     
          C = 
      getint();
     
    
- 
    
     
    
    
     
          q = 
      getint();
     
    
- 
    
     
    
    
         
      if (R > 
      1) {
     
    
- 
    
     
    
    
             
      for (
      int i = 
      1; i <= R; i++)
     
    
- 
    
     
    
    
                 
      for (
      int j = 
      1; j <= C; j++) {
     
    
- 
    
     
    
    
                     
      int x = 
      getint();
     
    
- 
    
     
    
    
                     
      for (
      int k = 
      1; k <= x; k++) {
     
    
- 
    
     
    
    
     
                          f[i][j][k] = f[i
      -1][j][k] + f[i][j
      -1][k] - f[i
      -1][j
      -1][k] + x;
     
    
- 
    
     
    
    
     
                          g[i][j][k] = g[i
      -1][j][k] + g[i][j
      -1][k] - g[i
      -1][j
      -1][k] + 
      1;
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
                     
      for (
      int k = x + 
      1; k <= 
      1000; k++) {
     
    
- 
    
     
    
    
     
                          f[i][j][k] = f[i
      -1][j][k] + f[i][j
      -1][k] - f[i
      -1][j
      -1][k];
     
    
- 
    
     
    
    
     
                          g[i][j][k] = g[i
      -1][j][k] + g[i][j
      -1][k] - g[i
      -1][j
      -1][k];
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
                  
     
    
- 
    
     
    
    
             
      while (q--) {
     
    
- 
    
     
    
    
                 
      int r1 = 
      getint(),c1 = 
      getint();
     
    
- 
    
     
    
    
                 
      int r2 = 
      getint(),c2 = 
      getint();
     
    
- 
    
     
    
    
                 
      int h = 
      getint();
     
    
- 
    
     
    
    
                 
      int l = 
      0,r = 
      1001;
     
    
- 
    
     
    
    
                 
      while (r - l > 
      1) {
     
    
- 
    
     
    
    
                     
      int mid = (l + r) >> 
      1;
     
    
- 
    
     
    
    
                     
      if (
      Judge(r1,c1,r2,c2,mid,h)) l = mid;
     
    
- 
    
     
    
    
                     
      else r = mid;
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
                 
      if (
      Judge(r1,c1,r2,c2,r,h)) 
      Print(r1,c1,r2,c2,r,h);
     
    
- 
    
     
    
    
                 
      else 
      if (
      Judge(r1,c1,r2,c2,l,h)) 
      Print(r1,c1,r2,c2,l,h);
     
    
- 
    
     
    
    
                 
      else 
      puts(
      "Poor QLW");
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      else {
     
    
- 
    
     
    
    
             
      for (
      int i = 
      1; i <= C; i++) {
     
    
- 
    
     
    
    
                 
      int x = 
      getint();
     
    
- 
    
     
    
    
     
                  root[i] = 
      Insert(root[i
      -1],
      1,
      1000,x);
     
    
- 
    
     
    
    
     
              } 
     
    
- 
    
     
    
    
             
      while (q--) {
     
    
- 
    
     
    
    
                 
      int r1 = 
      getint(),c1 = 
      getint();
     
    
- 
    
     
    
    
                 
      int r2 = 
      getint(),c2 = 
      getint();
     
    
- 
    
     
    
    
                 
      int h = 
      getint();
     
    
- 
    
     
    
    
                 
      int ans = 
      Query(root[c1
      -1],root[c2],
      1,
      1000,h);
     
    
- 
    
     
    
    
                 
      if (ans != 
      -1) 
      printf(
      "%d\n",ans);
     
    
- 
    
     
    
    
                 
      else 
      puts(
      "Poor QLW");
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      return 
      0;
     
    
- 
    
     
    
    
     
      }
     
    
 5 E - 森林
动态维护树上两点间第 k 值 LCT 不能直接维护第 k 值,也很难嵌套其他数据结构,所以我们不考虑它;发现只有 加边没有删边,考虑使用主席树启发式合并 具体来说, 加边时, 把节点少的主席树合并到节点多的主席树上面,复杂度 slogs,s 为 小主席树的大小, 同时动态更新父节点的倍增数组,复杂度也是 slogs 的 查询时, 进入两个点以及它们的 lca 和 lca 的爹的主席树中上上下下加加减减
  
   - 
    
     
    
    
     
      #include <cstdio>
     
    
- 
    
     
    
    
     
      #include <cstring>
     
    
- 
    
     
    
    
     
      #include <algorithm>
     
    
- 
    
     
    
    
     
      #define ls ch[now][0]
     
    
- 
    
     
    
    
     
      #define rs ch[now][1]
     
    
- 
    
     
    
    
     
      #define ols ch[las][0]
     
    
- 
    
     
    
    
     
      #define ors ch[las][1]
     
    
- 
    
     
    
    
     
      const 
      int N=
      3e5+
      10;
     
    
- 
    
     
    
    
     
      int ch[N*
     
    
- 
    
     
    
    
     
      30][
      2],sum[N*
     
    
- 
    
     
    
    
     
      30],tot;
     
    
- 
    
     
    
    
     
      int f[N][
      20],dep[N],n,m,n_,t,tmp,siz[N],root[N],a[N],b[N],testcase;
     
    
- 
    
     
    
    
     
      void updata(int now){sum[now]=sum[ls]+sum[rs];}
     
    
- 
    
     
    
    
     
      int rebuild(int las,int l,int r,int pos)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      int now=++tot;
     
    
- 
    
     
    
    
     
      if(l==r) {sum[now]+=sum[las]+
      1;
      return now;}
     
    
- 
    
     
    
    
     
      int mid=l+r>>
      1;
     
    
- 
    
     
    
    
     
      if(pos<=mid)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      ls=
      rebuild(ols,l,mid,pos);
     
    
- 
    
     
    
    
     
      rs=ors;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      else
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      ls=ols;
     
    
- 
    
     
    
    
     
      rs=
      rebuild(ors,mid+
      1,r,pos);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      updata(now);
     
    
- 
    
     
    
    
     
      return now;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      int head[N],to[N<<
      1],Next[N<<
      1],cnt;
     
    
- 
    
     
    
    
     
      void add(int u,int v)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      int dfs(int now,int fa)
     
    
- 
    
     
    
    
     
      12
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      int s=
      1;
     
    
- 
    
     
    
    
     
      root[now]=
      rebuild(root[fa],
      1,n,b[now]);
     
    
- 
    
     
    
    
     
      f[now][
      0]=fa;
     
    
- 
    
     
    
    
     
      dep[now]=dep[fa]+
      1;
     
    
- 
    
     
    
    
     
      for(
      int i=
      1;i<=
      18;i++)
     
    
- 
    
     
    
    
     
      f[now][i]=f[f[now][i−
      1]][i−
      1];
     
    
- 
    
     
    
    
     
      for(
      int i=head[now];i;i=Next[i])
     
    
- 
    
     
    
    
     
      if(to[i]!=fa)
     
    
- 
    
     
    
    
     
      s+=
      dfs(to[i],now);
     
    
- 
    
     
    
    
     
      return s;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      void swap(int &x,int &y){tmp=x,x=y,y=tmp;}
     
    
- 
    
     
    
    
     
      int rt(int now)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      for(
      int i=
      18;~i;i−−)
     
    
- 
    
     
    
    
     
      if(f[now][i])
     
    
- 
    
     
    
    
     
      now=f[now][i];
     
    
- 
    
     
    
    
     
      return now;
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      void Merge(int x,int y)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      int rx=
      rt(x),ry=
      rt(y);
     
    
- 
    
     
    
    
     
      if(siz[rx]<siz[ry]) 
      swap(rx,ry),
      swap(x,y);
     
    
- 
    
     
    
    
     
      add(x,y),
      add(y,x);
     
    
- 
    
     
    
    
     
      siz[rx]+=
      dfs(y,x);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      int LCA(int x,int y)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      if(dep[x]<dep[y]) 
      swap(x,y);
     
    
- 
    
     
    
    
     
      for(
      int i=
      18;~i;i−−)
     
    
- 
    
     
    
    
     
      if(dep[f[x][i]]>=dep[y])
     
    
- 
    
     
    
    
     
      x=f[x][i];
     
    
- 
    
     
    
    
     
      if(x==y) 
      return x;
     
    
- 
    
     
    
    
     
      for(
      int i=
      18;~i;i−−)
     
    
- 
    
     
    
    
     
      if(f[x][i]!=f[y][i])
     
    
- 
    
     
    
    
     
      x=f[x][i],y=f[y][i];
     
    
- 
    
     
    
    
     
      return f[x][
      0];
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      int query(int rt1,int rt2,int rt3,int rt4,int l,int r,int k)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      if(l==r) 
      return a[l];
     
    
- 
    
     
    
    
     
      int mid=l+r>>
      1,s=sum[ch[rt1][
      0]]+sum[ch[rt2][
      0]]−sum[ch[rt3][
      0]]−sum[ch[rt4
     
    
- 
    
     
    
    
     
      ][
      0]];
     
    
- 
    
     
    
    
     
      if(s>=k) 
      return 
      query(ch[rt1][
      0],ch[rt2][
      0],ch[rt3][
      0],ch[rt4][
      0],l,mid,k);
     
    
- 
    
     
    
    
     
      else 
      return 
      query(ch[rt1][
      1],ch[rt2][
      1],ch[rt3][
      1],ch[rt4][
      1],mid+
      1,r,k−s);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      int main()
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      scanf(
      "%d",&testcase);
     
    
- 
    
     
    
    
     
      tot=
      0,cnt=
      0;
     
    
- 
    
     
    
    
     
      scanf(
      "%d%d%d",&n_,&m,&t);
     
    
- 
    
     
    
    
     
      for(
      int i=
      1;i<=n_;i++) 
      scanf(
      "%d",a+i),b[i]=a[i];
     
    
- 
    
     
    
    
     
      std::
      sort(a+
      1,a+
      1+n_);
     
    
- 
    
     
    
    
     
      n=std::
      unique(a+
      1,a+
      1+n_)−a−
      1;
     
    
- 
    
     
    
    
     
      for(
      int i=
      1;i<=n_;i++) b[i]=std::
      lower_bound(a+
      1,a+
      1+n,b[i])−a;
     
    
- 
    
     
    
    
     
      for(
      int u,v,i=
      1;i<=m;i++)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      scanf(
      "%d%d",&u,&v);
     
    
- 
    
     
    
    
     
      add(u,v),
      add(v,u);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      for(
      int i=
      1;i<=n_;i++)
     
    
- 
    
     
    
    
     
      if(!f[i][
      0])
     
    
- 
    
     
    
    
     
      siz[i]=
      dfs(i,
      0);
     
    
- 
    
     
    
    
     
      int lastans=
      0;
      char op[
      4];
     
    
- 
    
     
    
    
     
      for(
      int u,v,k,i=
      1;i<=t;i++)
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      scanf(
      "%s%d%d",op,&u,&v);
     
    
- 
    
     
    
    
     
      u^=lastans,v^=lastans;
     
    
- 
    
     
    
    
     
      if(op[
      0]==
      'Q')
     
    
- 
    
     
    
    
     
      {
     
    
- 
    
     
    
    
     
      scanf(
      "%d",&k);
     
    
- 
    
     
    
    
     
      k^=lastans;
      int lca=
      LCA(u,v);
     
    
- 
    
     
    
    
     
      printf(
      "%d\n",lastans=
      query(root[u],root[v],root[lca],root[f[lca][
      0]],
      1,n,
     
    
- 
    
     
    
    
     
      k));
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      else
     
    
- 
    
     
    
    
     
      Merge(u,v);
     
    
- 
    
     
    
    
     
      }
     
    
- 
    
     
    
    
     
      return 
      0;
     
    
- 
    
     
    
    
     
      }
     
    
 转载:https://blog.csdn.net/m0_61735576/article/details/128553874
 
					