您的位置:首页 > 其它

【BZOJ 3932】[CQOI2015]任务查询系统

2017-04-26 08:32 288 查看

题目来源:BZOJ 3932

思路:

类似于在区间上标记线段的操作,把所有的区间变成两个点,边操作边进行前缀和就好了,需要用用主席树维护的信息有权值的出现次数,权值的和。

特别注意,在处理答案的时候,最后一个节点可能有多种状态,有可能只选择其中的一部分,需要特判一下。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define mid ((l+r)>>1)
using namespace std;
const int maxn = 100010;
typedef long long ll;
struct node{
int time, val;
bool operator < (const node &tt)const{return time < tt.time;}
} p[maxn*2];
struct Tree{
int num, sum;
Tree *ch[2];
} T[maxn*40], *root[maxn*2];
int n, m, cnt, nxt, ct, _tm;
int val[maxn], last[maxn], tm[maxn];
ll Pre = 1;
ll gt(){
char c = ' '; ll num = 0; bool ok = 0;
while(1){
c = getchar();
if(c <= '9' && c >= '0') num = num * 10 + c - '0', ok = 1;
else if(ok) return num;
}
}
int find(int ee[], int l, int r, int v){
int ans = 0;
while(l <= r){
if(ee[mid] <= v) ans = mid, l = mid + 1;
else r = mid - 1;
}
return ans;
}
int abs(int x){return x < 0 ? -x : x;}
Tree* get(){return &T[++nxt];}
void made(Tree* now, int l, int r){
if(l == r) return;
made(now->ch[0] = get(), l, mid);
made(now->ch[1] = get(), mid+1, r);
}
void build(Tree* now, Tree* pre, int k, int Num, int Sum, int l, int r){
if(l == r) <
4000
span class="hljs-keyword">return;
int wh = 1; if(k <= mid) wh = 0;
now->ch[wh^1] = pre->ch[wh^1];
now->ch[wh] = get();
now->ch[wh]->num = pre->ch[wh]->num + Num;
now->ch[wh]->sum = pre->ch[wh]->sum + Sum;
build(now->ch[wh], pre->ch[wh], k, Num, Sum,
wh == 0 ? l : mid+1, wh == 0 ? mid : r);
}
ll ask(Tree* now, int k, int l, int r){
if(l == r){
// 这里特判。
if(now->num) return now->sum / now->num * k;
return now->sum;
}
if(k <= now->ch[0]->num) return ask(now->ch[0], k, l, mid);
else return now->ch[0]->sum + ask(now->ch[1], k-now->ch[0]->num, mid+1, r);
}
int main(){
scanf("%d%d", &m, &n);
for(int i = 1; i <= m; i ++){
int a = gt(), b = gt(), c = gt();
p[++cnt].time = a, p[cnt].val = c;
p[++cnt].time = b+1, p[cnt].val = -c;
val[++ct] = c;
}
// 按时间排序
sort(p+1, p+1+cnt);
// 离散化
sort(val+1, val+1+ct);
ct = unique(val+1, val+1+ct) - (val+1);
// 建树
root[0] = get(); made(root[0], 1, ct);
for(int i = 1; i <= cnt; i ++){
last[p[i].time] = i;
int pos = find(val, 1, ct, abs(p[i].val));
root[i] = get();
build(root[i], root[i-1], pos, p[i].val > 0 ? 1:-1, p[i].val, 1, ct);
}
for(int i = 1; i <= n; i ++)
if(last[i] != 0) tm[++_tm] = i;

// 查询
for(int i = 1; i <= n; i ++){
ll ti = gt(), a = gt(), b = gt(), c = gt(), ki;
ti = tm[find(tm, 1, _tm, ti)];
ki = (((a%c)*(Pre%c))%c+(b%c))%c + 1;
Pre = ask(root[last[ti]], ki, 1, ct);
printf("%lld\n", Pre);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: