【解题报告】HDU 6602 Longest Subarray(思维,线段树的应用,线段树上二分)

原题地址
借鉴dalao的博客

体

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <queue>
#include <cstring>
#include <stack>
#define lson rt<<1
#define rson rt<<1|1
const static int maxn = 1e5+10;
using namespace std;
typedef long long ll;

int n, c, k;

struct segmenttree
{
    ll mx;
    ll mark;
}st[maxn<<2];

vector <int> pos[maxn];
int a[maxn];

void pushup(int rt)
{
    st[rt].mx = max(st[lson].mx, st[rson].mx);
}

void pushdown(int rt)
{
    if(st[rt].mark != 0)
    {
        st[lson].mark = st[rson].mark = st[rt].mark;
        st[lson].mx += st[lson].mark;
        st[rson].mx += st[rson].mark;
        st[rt].mark = 0;
    }
}

void buildtree(int l, int r, int rt)
{
    st[rt].mark = 0;
    if(l == r)
    {
        st[rt].mx = 0;
        return;
    }
    int m = (l + r) >> 1;
    buildtree(l, m, lson);
    buildtree(m+1, r, rson);
    pushup(rt);
}

void update(int _l, int _r, int l, int r, int rt, int val)
{
    if(_l > _r)
        return;
    //cout<<_l<<" "<<_r<<" "<<l<<" "<<r<<" "<<rt<<endl;
    if(_l <= l && _r >= r)
    {
        st[rt].mx += val;
        //cout<<l<<" "<<r<<endl;
        st[rt].mark += val; // 这里要用加的
        return;
    }
    pushdown(rt);
    int m = (l + r) >> 1;
    if(_l <= m)
        update(_l, _r, l, m, lson, val);
    if(_r > m)
        update(_l, _r, m+1, r, rson, val);
    pushup(rt);
}
int query(int l, int r, int rt)
{
    if(l == r)
        return l;
    pushdown(rt);
    int ans = -1;
    int m = (l + r) >> 1;
    if(st[lson].mx == c)
        ans = query(l, m, lson);
    else if(st[rson].mx == c)
        ans = query(m+1, r, rson);
    return ans;
}
int num[maxn];

int main()
{
    while(scanf("%d %d %d", &n, &c, &k) != EOF)
    {
        memset(num, 0, sizeof num);
        for(int i=1; i<=c; i++)
        {
            pos[i].clear();
            pos[i].push_back(0);
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            pos[a[i]].push_back(i);
        }
        buildtree(1, n, 1);
        for(int i=1; i<=c; i++)
        {
            pos[i].push_back(n+1);
            //cout<<pos[i][1]<<endl;
            update(1, pos[i][1]-1, 1, n, 1, 1);
            num[i] = 0;
        }
        int ans = 0;
        for(int i=1; i<=n; i++)
        {
            int t = a[i];
            update(pos[t][num[t]]+1, pos[t][num[t]+1]-1, 1, n, 1, -1);//这样写起来思路清晰,去掉已经不满足的区间,再加上新满足的区间,
                                                                      //由于log实现,所以我们可以尽量用线段树的相关操作,避免出错。
            if(num[t] >= k)
                update(1, pos[t][num[t]-k+1], 1, n, 1, -1);
            num[t]++;
            update(pos[t][num[t]]+1, pos[t][num[t]+1]-1, 1, n, 1, 1);
            if(num[t] >= k)
                update(1, pos[t][num[t]-k+1], 1, n, 1, 1);
            int temp = query(1, n ,1);
            if(temp != -1)
                ans = max(ans, i-temp+1);
        }
        printf("%d\n", ans);
    }
    return 0;
}

/*
7 4 2
2 1 4 1 4 3 2
*/

挖坑

做这道题体会太多,现在还太菜了,不能讲的很好,日后补上,只能说东西不能学死,像线段树这种东西,只能作为一种思想去学,不能认为会线段树就能解决线段树相关的东西,真正会灵活应用才是真正学会了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值