HDU6602 Longest Subarray hdu多校第二场 线段树

HDU6602 Longest Subarray 线段树

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6602

题意:

给你一段区间,让你求最长的区间使得区间出现的数字的个数大于k

题解:

比较巧妙的的线段树更新的做法

我们选择的区间吗,该区间内出现的数字的个数必须要满足条件

我们转换一下,我们以当前点为右端点,往左找一个满足条件的左端点,即可更新答案

我们将每个点给予一个权值C-1,更新这个点的数字上次出现的位置之前到现在这个位置-1的一段减1

如果满足这个点的值出现的次数大于k次的话,我们将上一次满足出现k次出现的一段位置给加上1

最后得到当前位置之前满足条件的左端点更新答案

这里巧妙的使用了条件作为线段树查询的条件,所以线段树查询出来的左端点就是满足条件的最远的左端点

代码:

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
/*
如果右端点固定,对于每种元素,可行的左端点下标是两段连续的区间。
对于每种元素,将它的可行左端点区间在线段树中加1。
 当右端点右移的时候,维护C 种元素的可行左端点。
查询时只要询问线段树中札小的、值为C 的下标即可。*/
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
int n, C, k;
int Max[maxn << 2];
int lazy[maxn << 2];
int pos[maxn << 2];
void push_up(int rt) {
    Max[rt] = max(Max[ls], Max[rs]);
    pos[rt] = (Max[rt] == Max[ls] ? pos[ls] : pos[rs]);
}
void build(int l, int r, int rt) {
    Max[rt] = lazy[rt] = 0;
    pos[rt] = l;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
}
void push_down(int rt) {
    if(lazy[rt]) {
        lazy[ls] += lazy[rt];
        lazy[rs] += lazy[rt];
        Max[ls] += lazy[rt];
        Max[rs] += lazy[rt];
        lazy[rt] = 0;
    }
}
void update(int L, int R, int val, int l, int r, int rt) {
    if(L > R) return;
    if(L <= l && r <= R) {
        Max[rt] += val;
        lazy[rt] += val;
        return;
    }
    push_down(rt);
    int mid = (l + r) >> 1;
    if(L <= mid) update(L, R, val, lson);
    if(R > mid) update(L, R, val, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if(Max[rt] != C) return 0;
    if(L <= l && r <= R) {
        return pos[rt];
    }
    int mid = (l + r) >> 1;
    push_down(rt);
    if(L <= mid) {
        int t = query(L, R, lson);
        if(t) return t;
    }
    if(R > mid) return query(L, R, rson);
    return 0;
}
vector<int> vec[maxn];
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    while(scanf("%d%d%d", &n, &C, &k) != EOF) {
        for(int i = 1; i <= C; i++) {
            vec[i].clear();
            vec[i].push_back(0);
        }
        build(1, n, 1);
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            int c;
            scanf("%d", &c);
            update(i, i, C - 1, 1, n, 1);
            update(vec[c].back() + 1, i - 1, -1, 1, n, 1);
            vec[c].push_back(i);
            int p = vec[c].size() - k - 1;
            if(p >= 0) {
                update(vec[c][p] + 1, vec[c][p + 1], 1, 1, n, 1);
            }
            int j = query(1, i, 1, n, 1);
            if(!j) continue;
            ans = max(ans, i - j + 1);
        }
        printf("%d\n", ans);

    }

    return 0;
}

原文地址:https://www.cnblogs.com/buerdepepeqi/p/11253492.html

时间: 2024-11-11 08:19:14

HDU6602 Longest Subarray hdu多校第二场 线段树的相关文章

2018 hdu 多校 第二场

因为3点半才来(其实是3点50,刚刚到酒店就开始了= =队友也是一个那时刚刚睡醒= = 1004 小甜甜 全部yes就好了 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include

多校第二场 简单排序计算

思路:先按交叉相乘之差排序好了计算就行了. #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <map> #include <cstdlib> #include <queue> #include <stack> #include <vector> #include <ctype.

hdu 1540 Tunnel Warfare【线段树】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目大意:抗日战争时期,各村庄被一条地道连接着(村庄排在一条线上),有三种操作: 第一种:某村庄被敌军摧毁: 第二种:修复上一个被摧毁的村庄: 第三种:查询与该村庄直接或间接链接的村庄有多少个(包括自己): 此题用线段树做,每个节点包含该区间从左端开始有多大连续区间ls,从右端向左有多大连续区间rs,该区间的最大连续区间mas: 代码如下: #include <iostream> #incl

hdu 1754 I Hate It 线段树单点更新和区间求和

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 参照HH大牛写的额! Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有时候需要更新某位同学的成绩. Input 本题目包含多

hdu 5861 Road 两棵线段树

传送门:hdu 5861 Road 题意: 水平线上n个村子间有 n-1 条路. 每条路开放一天的价格为 Wi 有 m 天的操作,每天需要用到村子 Ai~Bi 间的道路 每条路只能开放或关闭一次. (不能重复开关) 求每天的最小花费. 思路: 第一次线段树:维护每条路第一次和最后一次被用到的天数.以下代码维护了 mn:第一次被用到,mx:最后一次被用到,lazy:被更新的最大值若当前区间被lazy维护而没有更新到点,那么这个子节点的最小值就可能被改变.所以我这里的子节点更新是根据父节点的最大和最

HDU 1754-I Hate It(线段树:单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 39163    Accepted Submission(s): 15507 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师

HDU 1754 I Hate It(线段树)

Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有时候需要更新某位同学的成绩. Input 本题目包含多组测试,请处理到文件结束. 在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目. 学生ID编号分别从1编到N. 第二

hdu 1754 I Hate It 线段树 点修改

// hdu 1754 I Hate It 线段树 点修改 // // 不多说,裸的点修改 // // 继续练 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits> #include <cmath> #include <complex> #i

HDU 4902 Nice boat(线段树 区间更新)

Nice boat 大意:给你一个区间,每次可以进行两种操作,1:把区间中的数全都变成x  2:把区间中大于x的数变成gcd(a[i], x),最后输出序列. 思路:线段树成段更行,用num数组的叶子存储数据,节点当作lazy来使用. 1 #include <stdio.h> 2 const int maxn = 100005; 3 4 int num[maxn<<2]; 5 6 int gcd(int a, int b){ 7 return b?gcd(b, a%b):a; 8