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. Android判断网络是否连接

    <!-- 配置文件判断网络是否连接 --> <uses-permission android:name="android.permission.ACCESS_NETWORK ...

  2. window.parent与window.openner 之前的总结

    今天总结一下js中几个对象的区别和用法: 1.首先来说说 parent.window与top.window的用法 "window.location.href","loca ...

  3. PHP 逻辑思维题

    约瑟夫环 一群猴子排成一圈,按1,2,...,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去...,如此不停的进行下去,直到最后只剩下一只猴子为止 ...

  4. VirtualBox共享文件夹等高级特性

    转自: http://blog.csdn.net/longerzone/article/details/32119457 http://www.oschina.net/translate/10-vir ...

  5. JavaScript String 对象方法

    String 对象方法 方法 描述 anchor() 创建 HTML 锚. big() 用大号字体显示字符串. blink() 显示闪动字符串. bold() 使用粗体显示字符串. charAt() ...

  6. Product of Array Exclude Itself

    Given an integers array A. Define B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1], calculate B WI ...

  7. tcp ip detatils

    tcp ip detatils 8.关于TCP协议,下面哪种说法是错误的()A.TCP关闭连接过程中,两端的socket都会经过TIME_WAIT状态B.对一个Established状态的TCP连接, ...

  8. Solr5.3.1整合IKAnalyzer

    由于solr5.3.1本身不支持中文分词,而msseg4j的分词效果不明显.因而采用IK进行分词,然而参考http://www.superwu.cn/2015/05/08/2134/在google上下 ...

  9. CAS单点登录之mysql数据库用户验证及常见问题

    前面已经介绍了CAS服务器的搭建,详情见:搭建CAS单点登录服务器.然而前面只是简单地介绍了服务器的搭建,其验证方式是原始的配置文件的方式,这显然不能满足日常的需求.下面介绍下通过mysql数据库认证 ...

  10. Java for LeetCode 067 Add Binary

    Given two binary strings, return their sum (also a binary string). For example, a = "11" b ...