hdu 4638 Group(莫队算法|离线线段树)

Group

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1323    Accepted Submission(s): 703

Problem Description

There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group
can create K*K value. The value of an interval is sum of these value of groups. The people of same group‘s id must be continuous. Now we chose an interval of men and want to know there should be how many groups so the value of interval is
max.

Input

First line is T indicate the case number.

For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query.

Then a line have n number indicate the ID of men from left to right.

Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].

Output

For every query output a number indicate there should be how many group so that the sum of value is max.

Sample Input

1
5 2
3 1 2 5 4
1 5
2 4

Sample Output

1
2

Source

2013 Multi-University Training Contest 4

Recommend

zhuyuanchen520   |   We have carefully selected several similar problems for you:  4996 4995 4994 4993 4992

题意:

给你一个长度为n(1<=n<=100000)的数列。数列中的值互不相同且1<=ai<=n。对于一个给定的区间。[L,R]ans就为

下标[L,R]的数。中取值连续的块的块数。比如。1,3,2,6,8,7块数就为2。1,2,3一块。6,7,8为一块。

思路:

由于知道[L,R]的答案可以得到附近区间的答案。就想用莫队水一发。但是维护区间内有多少块是用线段树维护的。结果不言而喻。。其实不用线段树的。直接开个bool数组。如果i出现了就把vis[i]置为1.判断块数就简单了。加入一个数的时候如果vis[i-1]和vis[i+1]都为1的话那么块数ans就要-1.如果只有一个为1的话ans不变。如果全为0的话ans+1.

删除一个数类似处理就行了。

详细见代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
typedef long long ll;
struct qnode
{
    int l,r,idx;
} qu[maxn];
int id[maxn],pos[maxn],ans[maxn],bks;
bool vis[maxn];
bool cmp(qnode a,qnode b)
{
    if(pos[a.l]==pos[b.l])
        return a.r<b.r;
    return pos[a.l]<pos[b.l];
}
void update(int x,bool d)
{
    vis[x]=d;
    if(d)
        bks+=1-vis[x-1]-vis[x+1];
    else
        bks+=vis[x-1]+vis[x+1]-1;
}
int main()
{
    int t,n,m,i,j,bk,pl,pr,pp;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(vis,0,sizeof vis);
        bk=ceil(sqrt(1.0*n));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&id[i]);
            pos[i]=(i-1)/bk;
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&qu[i].l,&qu[i].r);
            qu[i].idx=i;
        }
        sort(qu,qu+m,cmp);
        pl=1,pr=0,bks=0;
        for(i=0;i<m;i++)
        {
            pp=qu[i].idx;
            if(pr<qu[i].r)
            {
                for(j=pr+1;j<=qu[i].r;j++)
                    update(id[j],1);
            }
            else
            {
                for(j=pr;j>qu[i].r;j--)
                    update(id[j],0);
            }
            if(pl<qu[i].l)
            {
                for(j=pl;j<qu[i].l;j++)
                    update(id[j],0);
            }
            else
            {
                for(j=pl-1;j>=qu[i].l;j--)
                    update(id[j],1);
            }
            pl=qu[i].l,pr=qu[i].r;
            ans[pp]=bks;
        }
        for(i=0;i<m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

开始的线段树代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
typedef long long ll;
#define lson L,mid,ls
#define rson mid+1,R,rs
struct qnode
{
    int l,r,idx;
} qu[maxn];
int id[maxn],bks[maxn<<1],ml[maxn<<1],mr[maxn<<1],pos[maxn],ans[maxn];
bool cmp(qnode a,qnode b)
{
    if(pos[a.l]==pos[b.l])
        return a.r<b.r;
    return pos[a.l]<pos[b.l];
}
void build(int L,int R,int rt)
{
    bks[rt]=ml[rt]=mr[rt]=0;
    if(L==R)
        return;
    int ls=rt<<1,rs=ls|1,mid=(L+R)>>1;
    build(lson);
    build(rson);
}
void update(int L,int R,int rt,int p,int d)
{
    if(L==R)
    {
        bks[rt]=ml[rt]=mr[rt]=d;
        return;
    }
    int ls=rt<<1,rs=ls|1,mid=(L+R)>>1;
    if(p<=mid)
        update(lson,p,d);
    else
        update(rson,p,d);
    bks[rt]=bks[ls]+bks[rs];
    ml[rt]=ml[ls];
    mr[rt]=mr[rs];
    if(mr[ls]&&ml[rs])
        bks[rt]--;
}
int qubks(int L,int R,int rt,int l,int r)
{
    if(l<=L&&R<=r)
        return bks[rt];
    int ls=rt<<1,rs=ls|1,mid=(L+R)>>1,tp=0,ct=0;
    if(l<=mid)
        tp+=qubks(lson,l,r),ct++;
    if(r>mid)
        tp+=qubks(rson,l,r),ct++;
    if(ct==2&&mr[ls]&&ml[rs])
        tp--;
    return tp;
}
int main()
{
    int t,n,m,i,j,bk,pl,pr,pp;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);
        bk=ceil(sqrt(1.0*n));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&id[i]);
            pos[i]=(i-1)/bk;
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&qu[i].l,&qu[i].r);
            qu[i].idx=i;
        }
        sort(qu,qu+m,cmp);
        pl=1,pr=0;
        for(i=0;i<m;i++)
        {
            pp=qu[i].idx;
            if(pr<qu[i].r)
            {
                for(j=pr+1;j<=qu[i].r;j++)
                    update(1,n,1,id[j],1);
            }
            else
            {
                for(j=pr;j>qu[i].r;j--)
                    update(1,n,1,id[j],0);
            }
            if(pl<qu[i].l)
            {
                for(j=pl;j<qu[i].l;j++)
                    update(1,n,1,id[j],0);
            }
            else
            {
                for(j=pl-1;j>=qu[i].l;j--)
                    update(1,n,1,id[j],1);
            }
            pl=qu[i].l,pr=qu[i].r;
            ans[pp]=qubks(1,n,1,1,n);
        }
        for(i=0;i<m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

离线线段树的方法还没写。写了再加上。。。,

时间: 2024-10-25 19:34:52

hdu 4638 Group(莫队算法|离线线段树)的相关文章

HDU 4638 Group (莫队算法||线段树离散查询)

题目地址:HDU 4638 先写了一发莫队,莫队可以水过.很简单的莫队,不多说. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <s

hdu 4638 Group 莫队算法

题目链接 很裸的莫队, 就不多说了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_pair(x, y) 6 #define lson l, m, rt<<1 7 #define mem(a) memset(a, 0, sizeof(a)) 8 #define rson m+1

莫队算法-离线查询区间内部不同数字的个数

#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std; const int maxx = 1e6+6; int a[maxx]; int vis[maxx]; int ans[maxx]; int block; int res; struct node { int l,r; i

[莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II

题目大意:给出一个长度为n的数列a. 对于一个询问lj和rj.将a[lj]到a[rj]从小到大排序后并去重.设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk.当中F为斐波那契数列.F1=F2=1.对每一个询问输出答案模m. 区间查询离线 用莫队算法 开棵权值线段树,然后用斐波那契的性质update F(n+m)=F(n+1)*F(m)+F(n)*F(m-1); #include<cstdio> #include<cstdlib> #includ

莫队算法(离线)

何谓莫队算法 莫队算法是莫涛队长发明的,为表示对他的尊敬,故称这种算法叫莫队. 适用范围 一种处理序列操作的离线算法,适用范围广,复杂度一般带根号. 莫队算法的思路 假设题目不涉及修改操作. 将所有操作离线,将所有操作进行二元组排序,第一维是左端点所在块的编号,第二维是右端点. 排序后,按照顺序处理询问,维护一个双端队列,同时维护队列内区间的答案,每次从$[L,R]$的答案,扩展到$[L-1,R]$ $[L,R-1]$ $[L+1,R]$ $[L,R+1]$的答案,最终得到当此询问区间的答案.

HDU 6278 - Just h-index - [莫队算法+树状数组+二分][2018JSCPC江苏省赛C题]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6278 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others) Problem Description The h-index of an author is the largest h where he has at least h papers with citations not les

hdu 5273 Dylans loves sequence(区间逆序对数-莫队算法)

n<=1000,q<=100000,求区间内逆序对数,从[l,r]显然可以log(n)的时间内移动到[l-1,r],[l+1,r],[l,r-1],[l,r+1],那么就可以用莫队进行离线 复杂度大概是O(n*sqrt(n)*log2(n)),不过可以暴力枚举起点,然后向后统计,然后O(1)回答,不过n再大就无法解决了,这个即使是n<=1e5也可以很快得到答案,开-o优化,1e6也可以很快得到答案 #include<bits/stdc++.h> using namespace

HDU 5145 NPY and girls(莫队算法+乘法逆元)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5145 [题目大意] 给出一个数列,每次求一个区间数字的非重排列数量.答案对1e9+7取模. [题解] 我们发现每次往里加入一个新的数字或者减去一个新的数字,前后的排列数目是可以通过乘除转移的,所以自然想到用莫队算法处理.因为答案要求取模,所以在用除法的时候要计算逆元. [代码] #include <cstdio> #include <algorithm> #include <

D. Powerful array 离线+莫队算法 给定n个数,m次查询;每次查询[l,r]的权值; 权值计算方法:区间某个数x的个数cnt,那么贡献为cnt*cnt*x; 所有贡献和即为该区间的值;

D. Powerful array time limit per test 5 seconds memory limit per test 256 megabytes input standard input output standard output An array of positive integers a1,?a2,?...,?an is given. Let us consider its arbitrary subarray al,?al?+?1...,?ar, where 1?