OTZ做出题目的神犇。。断断续续改完了在这里存一下思路吧

A题:第K大区间
题意:
定义一个区间的值为其众数出现的次数
现给出n个数,求将所有区间的值排序后,第K大的值为多少。 分析:
二分答案mid,任务就是判定有多少个区间的众数≥mid。
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn = 100010;

int n, A[maxn], c[maxn], cnt[maxn], mx, tmp[maxn];
ll k; void Add(int x){
cnt[c[x]] --;
c[x] ++;
cnt[c[x]] ++;
mx = max(mx, c[x]);
} void Del(int x){
cnt[c[x]] --;
c[x] --;
cnt[c[x]] ++;
while(!cnt[mx])mx --;
} int check(int x){
ll ans = 0, l = 1; mx = 0;
memset(cnt, 0, sizeof cnt);
memset(c, 0, sizeof c);
cnt[0] = n;
for(int i = 1; i <= n; i ++){
Add(A[i]);
while(true){
Del(A[l]);
if(mx < x) {Add(A[l]); break;}
l ++;
}
if(mx >= x) ans += l;
}
return ans >= k;
} int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++){
scanf("%d", &A[i]);
tmp[i] = A[i];
}
sort(tmp+1, tmp+1+n);
int p = unique(tmp+1, tmp+1+n) - tmp - 1;
for(int i = 1; i <= n; i ++)
A[i] = lower_bound(tmp+1, tmp+1+p, A[i]) - tmp;
int l = 1, r = n+1;
while(l < r){
int mid = l + (r - l + 1) / 2;
if(check(mid))l = mid;
else r = mid - 1;
}
printf("%d\n", l);
return 0;
}

  

 
 
B题戳这里
C题:逛街 分析:
对于喜欢的店的个数一定要大于等于k,这个可以用一个堆来贪心,维护堆中的元素等于k个,对于其他的离散化一下扔进线段树(splay也不介意,但是好像会t)
然后在线段树上二分
注意val有负值a。。然后不能加a
#include <bits/stdc++.h>
#define maxn 200010
using namespace std;
typedef long long ll;
int n, T, k, root, smz; int A[maxn], B[maxn], C[maxn];
long long sum[maxn]; priority_queue<pair<ll, int> > Q; int b[maxn]; struct Hash{
int id, p;
ll val;
bool operator<(const Hash& k)const{return val < k.val;}
}h[maxn]; bool cmp(const Hash& a, const Hash& b){return a.p < b.p;} struct Node{
int l, r, size; ll sum;
}t[maxn << 2];
#define lc id<<1
#define rc id<<1|1
void build(int id, int l, int r){
t[id].l = l, t[id].r = r;
if(l == r)return;
int mid = l+r >> 1;
build(lc, l, mid);
build(rc, mid+1, r);
} void pushup(int id){
t[id].sum = t[lc].sum + t[rc].sum;
t[id].size = t[lc].size + t[rc].size;
} void update(int id, int pos, ll val){
if(val < 0)return;
if(t[id].l == t[id].r){
t[id].sum = val;
t[id].size ++;
return;
}
int mid = t[id].l + t[id].r >> 1;
if(pos <= mid)update(lc, pos, val);
else update(rc, pos, val);
pushup(id);
} int ask(int id, ll T){
if(t[id].l == t[id].r)return min(t[id].size, (int)(T >= t[id].sum));
if(T >= t[lc].sum)return t[lc].size + ask(rc, T - t[lc].sum);
return ask(lc, T);
} int vis[maxn]; int main(){
scanf("%d%d%d", &n, &T, &k);
for(int i = 1; i <= n; i ++)scanf("%d", &A[i]);
for(int i = 1; i <= n; i ++)scanf("%d", &B[i]), h[i].val = B[i], h[i].p = i;
for(int i = 1; i <= n; i ++)scanf("%d", &C[i]); sort(h+1, h+1+n); for(int i = 1; i <= n; i ++)
h[i].id = i;
sort(h+1, h+1+n, cmp);
for(int i = 1; i <= n; i ++)b[i] = h[i].id;
build(1, 1, n);
int ans = 0;
ll Sum = 0;
for(int i = 1; i <= n; i ++){
if(C[i]){
if(Q.size() < k)Q.push(make_pair(B[i], i)), Sum += B[i];
else if(!Q.empty() && (Q.size() == k && B[i] < Q.top().first)){
ll t = Q.top().first;
int t1 = Q.top().second;Q.pop();
Q.push(make_pair(B[i], i));Sum = Sum - t + B[i];
update(1, b[t1], t);
}else update(1, b[i], B[i]);
}
else update(1, b[i], B[i]);
if(Q.size() >= k && Sum + A[i] <= T)ans = max(ans, k + ask(1, T - Sum - A[i]));
}
if(ans < k)puts("-1");
else printf("%d\n", ans);
return 0;
}

  

 
D题:Rikka with Sequences
题目大意:给定一个序列,有更改操作,每次查询一段区间的历史区间和最小值。
n, m ≤ 10^5, Ai ≤ 10^9
分析:
这个在线好难做a。所以就要离线la。所以就要用KD-tree啦。(QAQ)
对于每一个操作我们可以计算它对询问的贡献。把一个询问看成二维平面上的一个点(l, r),每一次操作都是将(pos, pos)左上角(l <= pos, r >= pos)的询问更改一下,通过打标记来实现历史最小值的询问。时光倒流,如果是每次给一个位置添加数字,询问历史最小值是个经典问题la
一定不要忘记pushdown。。。一定不要忘记mn[i]和mx[i]
#include <bits/stdc++.h>
#define maxn 100010
using namespace std; typedef long long ll; const int inf = 0x7fffffff; int n, m, dfs_clock, D;
//----------------------KD-tree--------------------------//
struct Node{
int l, r, mn[2], mx[2], d[2], id;
ll sum, add, ans, Minadd;
int& operator[](const int& k){return d[k];}
bool operator<(Node k)const{return d[D] < k[D];}
Node(int x = 0, int y = 0, int i = 0, ll s = 0){
sum = ans = s, id = i;
mn[0] = mx[0] = d[0] = x;
mn[1] = mx[1] = d[1] = y;
l = r = add = Minadd = 0;
}
}t[maxn], dfn[maxn], P;
int tot, root; void update(int o){
for(int i = 0; i < 2; i ++){
t[o].mn[i] = t[o].mx[i] = t[o][i];
if(t[o].l){
t[o].mn[i] = min(t[o].mn[i], t[t[o].l].mn[i]);
t[o].mx[i] = max(t[o].mx[i], t[t[o].l].mx[i]);
}
if(t[o].r){
t[o].mn[i] = min(t[o].mn[i], t[t[o].r].mn[i]);
t[o].mx[i] = max(t[o].mx[i], t[t[o].r].mx[i]);
}
}
} int Newnode(){
t[++ tot] = P;
return tot;
} inline void Down1(int o, ll val){
if(!o)return;
t[o].ans = min(t[o].ans, t[o].sum + val);
t[o].Minadd = min(t[o].Minadd, t[o].add + val);
} inline void Down2(int o, ll val){
if(!o)return;
t[o].ans = min(t[o].ans, t[o].sum += val);
t[o].Minadd = min(t[o].Minadd, t[o].add += val);
} inline void pushdown(int o){
if(t[o].Minadd){
Down1(t[o].l, t[o].Minadd), Down1(t[o].r, t[o].Minadd);
t[o].Minadd = 0;
} if(t[o].add){
Down2(t[o].l, t[o].add), Down2(t[o].r, t[o].add);
t[o].add = 0;
}
} void Modify(int o, int pos, ll val){
pushdown(o);
if(t[o].mx[0] <= pos && t[o].mn[1] >= pos) {Down2(o, val); return;}
if(t[o][0] <= pos && t[o][1] >= pos)t[o].sum += val, t[o].ans = min(t[o].ans, t[o].sum);
if(t[o].l && t[t[o].l].mn[0] <= pos && t[t[o].l].mx[1] >= pos)Modify(t[o].l, pos, val);
if(t[o].r && t[t[o].r].mn[0] <= pos && t[t[o].r].mx[1] >= pos)Modify(t[o].r, pos, val);
} void Insert(int o, int type){
pushdown(o), D = type;
if(P < t[o]){
if(t[o].l)Insert(t[o].l, type^1);
else t[o].l = Newnode();
}
else{
if(t[o].r)Insert(t[o].r, type^1);
else t[o].r = Newnode();
}
update(o);
} ll ans[maxn];
void dfs(int o){
pushdown(o);
dfn[++ dfs_clock] = t[o];
ans[t[o].id] = t[o].ans;
if(t[o].l)dfs(t[o].l);
if(t[o].r)dfs(t[o].r);
} int build(int l, int r, int type){
if(l > r)return 0; D = type;
int mid = l + r >> 1;
nth_element(dfn+l, dfn+mid, dfn+r+1);
t[mid] = dfn[mid];
t[mid].l = build(l, mid-1, type^1);
t[mid].r = build(mid+1, r, type^1);
update(mid); return mid;
} //----------------------query---------------------------//
int tp[maxn], l[maxn], r[maxn];
//----------------------BIT-----------------------------//
ll A[maxn], Bit[maxn];
#define lowbit(i) i&(~i+1)
void add(int pos, ll val){
for(int i = pos; i <= n; i += lowbit(i))
Bit[i] += val;
}
ll ask(int pos){
if(!pos)return 0;ll ret = 0;
for(int i = pos; i; i -= lowbit(i))
ret += Bit[i];
return ret;
}
//----------------------solve---------------------------//
int main(){
root = Newnode();
t[root].mn[0] = t[root].mn[1] = inf;
t[root].mx[0] = t[root].mx[1] = -inf;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%lld", &A[i]), add(i, A[i]);
for(int i = 1; i <= m; i ++){
scanf("%d%d%d", &tp[i], &l[i], &r[i]);
if(tp[i] == 1){
r[i] -= A[l[i]];//增量
A[l[i]] += r[i];
add(l[i], r[i]);
}
} int Buf = 2000;
for(int i = m; i >= 1; i --){
if(tp[i] == 1){
add(l[i], -r[i]);
Modify(root, l[i], -r[i]);
}
else{
P = Node(l[i], r[i], i, ask(r[i]) - ask(l[i]-1));
Insert(root, 0);
}
if(i % Buf == 0)dfs_clock = 0, dfs(root), root = build(1, dfs_clock, 0);
} dfs_clock = 0, dfs(root);
for(int i = 1; i <= m; i ++)
if(tp[i] == 2)printf("%lld\n", ans[i]);
return 0;
}

  

 
E题:小Z的Tire

广义后缀自动机。倍增找到位置输出parent树中子树节点个数
#include <bits/stdc++.h>
#define maxn 2000010
using namespace std; struct Node{int len, link, nxt[26];}st[maxn]; int root, size, last; int s[maxn]; void init(){
root = size = last = 0;
st[root].len = 0;
st[root].link = -1;
} void Extend(char ch){
int c = ch - 'a', p = last, q = st[p].nxt[c];
if(q){
if(st[q].len == st[p].len + 1)
last = q;
else{
int clone = ++ size;
st[clone] = st[q];
st[clone].len = st[p].len + 1;
for(; ~p && st[p].nxt[c] == q; p = st[p].link)
st[p].nxt[c] = clone;
st[q].link = clone;
last = clone;
}
}
else{
int cur = ++ size;
st[cur].len = st[p].len + 1;
for(; ~p && !st[p].nxt[c]; p = st[p].link)
st[p].nxt[c] = cur;
if(p == -1)
st[cur].link = root;
else{
q = st[p].nxt[c];
if(st[q].len == st[p].len + 1)
st[cur].link = q;
else{
int clone = ++ size;
st[clone] = st[q];
st[clone].len = st[p].len + 1;
for(; ~p && st[p].nxt[c] == q; p = st[p].link)
st[p].nxt[c] = clone;
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
s[last] = 1;
} int n; char c[maxn]; int anc[maxn][22]; int t[maxn], w[maxn]; void pre_anc(){
for(int i = 1; i <= size; i ++)w[st[i].len] ++;
for(int i = 1; i <= size; i ++)w[i] += w[i-1];
for(int i = 1; i <= size; i ++)t[w[st[i].len] --] = i;
for(int i = size; i >= 1; i --)s[st[t[i]].link] += s[t[i]]; memset(anc, -1, sizeof anc);
for(int i = 1; i <= size; i ++)
anc[i][0] = st[i].link;
for(int j = 1; 1 << j <= size; j ++){
for(int i = 1; i <= size; i ++){
int a = anc[i][j-1];
if(~a)anc[i][j] = anc[a][j-1];
}
}
} vector<int>V[100010]; int ask_pos(int r, int len){
int now = r;
for(int i = 21; i >= 0; i --){
int t = anc[now][i];
if(t == -1)continue;
if(st[t].len >= len)now = t;
}
return now;
} int main(){
init();
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
scanf("%s", c+1);
int N = strlen(c+1);
last = root;
for(int j = 1; j <= N; j ++){
Extend(c[j]);
V[i].push_back(last);
}
} pre_anc(); int m, u, v, d;
scanf("%d", &m);
for(int i = 1; i <= m; i ++){
scanf("%d%d%d", &u, &v, &d);
printf("%d\n", s[ask_pos(V[u][d-1], d-v+1)]);
}
return 0;
}

 

  

 

51NOD 算法马拉松12的更多相关文章

  1. 51nod算法马拉松12

    A 第K大区间 不妨考虑二分答案x,则问题转化成计算有多少个区间满足众数出现的次数>=x. 那么这个问题我们使用滑动窗口,枚举右端点,则左端点肯定单调递增,然后维护一个简单的数组就能资瓷添加元素 ...

  2. 51Nod 算法马拉松12 Rikka with sequences

    当时做比赛的时候听说过这类用KD_Tree维护的数据结构题 然后知道是KD_Tree,然而并不知道怎么写QAQ 比赛完了之后%了一发代码 其基本思路是这样的: 1.首先我们把询问[L,R]看成二维平面 ...

  3. 51Nod 算法马拉松12 移数博弈

    点进去发现并不是博弈QAQ 一开始考虑单调队列什么乱七八糟的发现根本做不出来 (没错我一直在想枚举最大值求次大值QAQ 不妨换个思路: 我们考虑枚举次大值求最大值 设当前为now, 设now之前第一个 ...

  4. 51NOD 算法马拉松8

    题目戳这里:51NOD算法马拉松8 某天晚上kpm在玩OSU!之余让我看一下B题...然后我就被坑进了51Nod... A.还是01串 水题..怎么乱写应该都可以.记个前缀和然后枚举就行了.时间复杂度 ...

  5. 51nod 算法马拉松 34 Problem D 区间求和2 (FFT加速卷积)

    题目链接  51nod 算法马拉松 34  Problem D 在这个题中$2$这个质数比较特殊,所以我们先特判$2$的情况,然后仅考虑大于等于$3$的奇数即可. 首先考虑任意一个点对$(i, j)$ ...

  6. 随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

    先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率 假 ...

  7. 51Nod 算法马拉松21(迎新年)

    这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过 ...

  8. 51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

    OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就 ...

  9. 51Nod 算法马拉松23 开黑记

    惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...

随机推荐

  1. snoopy 强大的PHP采集类使用实例代码

    下载地址: http://www.jb51.net/codes/33397.html Snoopy的一些特点: 1抓取网页的内容 fetch 2 抓取网页的文本内容 (去除HTML标签) fetcht ...

  2. 【Hibernate】Hibernate系列2之Session详解

    Session详解 2.1.概述-一级缓存 2.2.操作session缓存方法 2.3.数据库隔离级别 2.4.持久化状态 2.5.状态转换 2.6.存储过程与触发器

  3. poj 1318

    http://poj.org/problem?id=1318 这个题目还是比较水的,不过也可以提升你对字符串的熟悉度以及对一些排序函数和字符函数的使用. 大概的题意就是给你一个字典,这个字典有一些单词 ...

  4. 22.python笔记之web框架

    一.web框架本质 1.基于socket,自己处理请求 #!/usr/bin/env python3 #coding:utf8 import socket def handle_request(cli ...

  5. ubuntu dpkg 命令详解

    linux的包管理有多种,除了rpm,apt等还有优秀的dpkg,下面是dpkg命令的详细使用教程,希望对你有用.deb包的管理是比较优秀的包管理工具,用的linux系统有 debian ubuntu ...

  6. JavaScript设计模式 - 迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  7. 使用webstorm调试node程序

    前言 相信大家接触过不少node代码了,如果你应用的比较初级或者针对你的项目不需要接触过深的node代码,也许你仅仅需要简单的console.log('your variable')就完全满足你的需要 ...

  8. python实现简单爬虫抓取图片

    最近在学习python,正如大家所知,python在网络爬虫方面有着广泛的应用,下面是一个利用python程序抓取网络图片的简单程序,可以批量下载一个网站更新的图片,其中使用了代理IP的技术. imp ...

  9. JUC回顾之-CyclicBarrier底层实现和原理

    1.CyclicBarrier 字面意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时候,屏障才会开门.所有被 ...

  10. SQL中行列转换Pivot

    --建表 ),课程 ),分数 int) --插入数据 ) ) ) ) ) ) 1.静态行转列(确定有哪些列) select 姓名, end)语文, end)数学, end)物理 from tb gro ...