BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队

水果~~~~

关于四个while可行性的证明:区间有正确性所以不管那团小东西用没有duang~反它最终总会由于两次覆盖二准确

关于区间种数可行性的证明:他会在0 1间(或两边)来回跳动(过程中),最终会停在一个大于等于0的地方由于多次覆盖,最终也会趋于准确

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define M 1000005
#define N 100005
using namespace std;
int zero[N],a[N],b[N],pos[N],len,l,r,had[N],n,m;
struct Q
{
   int l,r,ans1,ans2,z,y,id;
}q[M];
int comp(const Q x,const Q y)
{
   return pos[x.l]<pos[y.l]||(pos[x.l]==pos[y.l]&&x.r<y.r);
}
int end_comp(const Q x,const Q y)
{
   return x.id<y.id;
}
inline void update_a(int x,int i)
{
   while(x<=n)
   {
     a[x]+=i;
     x+=x&(-x);
   }
}
inline void update_b(int x,int i)
{
   while(x<=n)
   {
     b[x]+=i;
     x+=x&(-x);
   }
}
inline int sum_a(int x)
{
   int ret=0;
   while(x>0)
   {
     ret+=a[x];
     x-=x&(-x);
   }
   return ret;
}
inline int sum_b(int x)
{
   int ret=0;
   while(x>0)
   {
     ret+=b[x];
     x-=x&(-x);
   }
   return ret;
}
void pre()
{
   scanf("%d%d",&n,&m);
   len=(int)(sqrt(n+0.5));
   for(int i=1;i<=n;i++)
   {
      scanf("%d",&zero[i]);
      pos[i]=(i-1)/len+1;
   }
   l=r=1;
   update_a(zero[1],1);
   update_b(zero[1],1);
   had[zero[1]]=1;
   for(int i=1;i<=m;i++)
   {
     scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].z,&q[i].y);
     q[i].id=i;
   }
   sort(q+1,q+m+1,comp);
}
inline void via(int pl,int i)
{
   if(i==1)
   {
     update_a(zero[pl],1);
     had[zero[pl]]++;
     if(had[zero[pl]]==1)
       update_b(zero[pl],1);
   }
   else
   {
     update_a(zero[pl],-1);
     had[zero[pl]]--;
     if(had[zero[pl]]==0)
       update_b(zero[pl],-1);
   }
}
void work()
{
   for(int i=1;i<=m;i++)
   {
      while(l<q[i].l)via(l++,-1);
      while(l>q[i].l)via(--l,1);
      while(r<q[i].r)via(++r,1);
      while(r>q[i].r)via(r--,-1);
      q[i].ans1=sum_a(q[i].y)-sum_a(q[i].z-1);
      q[i].ans2=sum_b(q[i].y)-sum_b(q[i].z-1);
   }
}
void print()
{
   sort(q+1,q+m+1,end_comp);
   for(int i=1;i<=m;i++)
    printf("%d %d\n",q[i].ans1,q[i].ans2);
}
int main()
{
    //freopen("ahoi2013_homework.in","r",stdin);
    //freopen("ahoi2013_homework.out","w",stdout);
    pre();
    work();
    print();
    return 0;
}
时间: 2024-10-12 08:05:46

BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队的相关文章

\BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1878 题意概括 给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数. 0<=数值<=1000000,n<=50000,m<=200000 题解 本题有许多做法. 这里介绍树状数组和莫队,都是离线算法. 树状数组 我们把序列按照R从小到大排序. 然后从左往右走. 依次加入数字,当前的状态,比如说搞定了前i个数字. 对于第i+1个数字,我们要给它做一个标记,但是不可

HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gcd种类不超过loga[i]种). 预处理gcd如下代码,感觉真的有点巧妙... 1 for(int i = 1; i <= n; ++i) { 2 int x = a[i], y = i; 3 for(int j = 0; j < ans[i - 1].size(); ++j) { 4 int g

ACdreamoj 1011(树状数组维护字符串hash前缀和)

题目链接:http://acdream.info/problem? pid=1019 题意:两种操作,第一种将字符串某个位置的字符换为还有一个字符.另外一种查询某个连续子序列是否是回文串: 解法:有两种hash的办法,所以写了两种解法;首先hash是x1 * p^1+ x2*p^2 +x3*p^3...能够用树状数组维护前缀和,维护两个串,一个是正串.还有一个是反串用于比較.比較时候乘以对应的p倍数推断是否相等. 刘汝佳白书上的hash方法处理这道题更复杂:改动i会对后缀j产生的影响为a*p^(

2018中国大学生程序设计竞赛 - 网络选拔赛 1010 YJJ&#39;s Salesman 【离散化+树状数组维护区间最大值】

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6447 YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 919    Accepted Submission(s): 290 Problem Description YJJ is a salesman who h

Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) C. Fountains 【树状数组维护区间最大值】

题目传送门:http://codeforces.com/contest/799/problem/C C. Fountains time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Arkady plays Gardenscapes a lot. Arkady wants to build two new fountains. The

Codeforces1076E. Vasya and a Tree(dfs+离线+树状数组维护)

题目链接:传送门 题目: E. Vasya and a Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Vasya has a tree consisting of n vertices with root in vertex 1. At first all vertices has 0 written on it.

树状数组维护前缀和

树状数组是用来维护序列前缀和的数据结构.它的修改与求和都是O(logn)的,效率非常高. 我们设序列为A,则树状数组c中,c[i]记录序列A的区间[ i-lowbit(i)+1 , i ]中所有数的和. (树状数组是个好东西ovo)  树状数组在进行区间操作时,要从上到下访问,进行单点操作时,要从下到上访问.  树状数组维护序列前缀和的模版如下: #include <iostream> #include <cstdio> #define maxn 500005 using name

Codeforces Round #629 (Div. 3) F - Make k Equal (离散化 树状数组维护前缀和)

https://codeforces.com/contest/1328/problem/F 首先把a数组处理成pair对(num,cnt),表示数字num有cnt个,然后按num升序排序离散化一下. 对于一个数x,若想使得小于x的数字都变成x,必须先把所有小于x的数变成x-1,然后再+1变成x. 同理,要使得大于x的数变成x,必须把所有大于x的数字变成x+1,然后再-1变成x. 以上是题意所要求的必须操作. 思路: 1. 用f[i]数组记录离散化后前i大的数字的总数,那么对于任意第i大数字,可以

树状数组维护前缀和、后缀和、个数|牛牛的Link Power

思路 另线段树做法:https://www.cnblogs.com/fisherss/p/12287606.html F题树状数组维护前缀即可 题目地址 https://ac.nowcoder.com/acm/contest/3004/F #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5+100; int n; char s[maxn]; const ll mod =