[Violet]蒲公英
题目背景
亲爱的哥哥:
你在那个城市里面过得好吗?
我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……
最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!
哥哥你要快点回来哦!
爱你的妹妹 Violet
Azure 读完这封信之后微笑了一下。
“蒲公英吗……”
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为 n n n 的序列 { a 1 , a 2 . . a n } \{a_1,a_2..a_n\} {a1,a2..an},其中 a i a_i ai 为一个正整数,表示第 i i i 棵蒲公英的种类编号。
而每次询问一个区间 [ l , r ] [l, r] [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
注意,你的算法必须是在线的。
输入格式
第一行有两个整数,分别表示蒲公英的数量 n n n 和询问次数 m m m。
第二行有 n n n 个整数,第 i i i 个整数表示第 i i i 棵蒲公英的种类 a i a_i ai。
接下来 m m m 行,每行两个整数 l 0 , r 0 l_0, r_0 l0,r0,表示一次询问。输入是加密的,解密方法如下:
令上次询问的结果为
x
x
x(如果这是第一次询问,则
x
=
0
x = 0
x=0),设
l
=
(
(
l
0
+
x
−
1
)
m
o
d
n
)
+
1
,
r
=
(
(
r
0
+
x
−
1
)
m
o
d
n
)
+
1
l=((l_0+x-1)\bmod n) + 1,r=((r_0+x-1) \bmod n) + 1
l=((l0+x−1)modn)+1,r=((r0+x−1)modn)+1。如果
l
>
r
l > r
l>r,则交换
l
,
r
l, r
l,r。
最终的询问区间为计算后的
[
l
,
r
]
[l, r]
[l,r]。
输出格式
对于每次询问,输出一行一个整数表示答案。
样例 #1
样例输入 #1
6 3
1 2 3 2 1 2
1 5
3 6
1 5
样例输出 #1
1
2
1
提示
数据规模与约定
- 对于 20 % 20\% 20% 的数据,保证 n , m ≤ 3000 n,m \le 3000 n,m≤3000。
- 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 40000 1\le n \le 40000 1≤n≤40000, 1 ≤ m ≤ 50000 1\le m \le 50000 1≤m≤50000, 1 ≤ a i ≤ 1 0 9 1\le a_i \le 10^9 1≤ai≤109, 1 ≤ l 0 , r 0 ≤ n 1 \leq l_0, r_0 \leq n 1≤l0,r0≤n。
answer
#include<bits/stdc++.h>
using namespace std;
const int N = 50070;
int n, t, m, cnt,preans = 0,M;
int a[N], b[N], pos[N], L[N], R[N], p[N], f[5070][5070];
vector<int>v[N];
void deal(int x) {
int now = 0;
for (int i = L[x]; i <= n; ++i) {//p存数字出现次数
++p[a[i]];
if (p[a[i]] > p[a[now]] || (p[a[i]] == p[a[now]] && a[i] < a[now]))
now = i;
f[x][pos[i]] = a[now];//f[a][b]表示从a到b块中的众数
}
memset(p, 0, sizeof p);
}
int query(int l, int r) {
int ans = 0, sum = 0, tot = 0, x, z, y;
if (pos[l] == pos[r])
for (int i = l; i <= r; ++i)
p[++tot] = a[i];
else {
for (int i = l; i <= R[pos[l]]; ++i)
p[++tot] = a[i];
p[++tot] = f[pos[l] + 1][pos[r] - 1];
for (int i = L[pos[r]]; i <= r; ++i)
p[++tot] = a[i];
}
for (int i = 1; i <= tot; ++i) {
if (!p[i])
continue;
x = p[i];
y = lower_bound(v[x].begin(), v[x].end(), l) - v[x].begin();
z = upper_bound(v[x].begin(), v[x].end(), r) - v[x].begin();
if (z - y + 1 > sum)
ans = x, sum = z - y + 1;
else if (z - y + 1 == sum && x < ans)
ans = x;
}
return b[ans];
}
int main() {
scanf("%d%d", &n,&M);
t = 150, cnt = n / t + !!(n % t); //!!:如果是0就是0,如果 > 0就是1,t是块长,卡常离谱
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
b[i] = a[i];
}
sort(b + 1, b + n + 1);//排序
m = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; ++i)//离散化
a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b;
for (int i = 1; i <= n; ++i)
v[a[i]].push_back(i);//存每个数的下标
for (int i = 1; i <= cnt; ++i)
L[i] = (i - 1) * t + 1, R[i] = i * t;
if (R[cnt] > n)
R[cnt] = n;
for (int i = 1; i <= cnt; ++i)
for (int j = L[i]; j <= R[i]; ++j)
pos[j] = i;
for (int i = 1; i <= cnt; ++i)
deal(i);
for (int i = 1, l, r; i <= M; ++i) {
scanf("%d%d", &l, &r);
l = (l + preans - 1) % n + 1,r = (r + preans - 1) % n + 1;
if(l > r)swap(l,r);
printf("%d\n", query(l, r));
preans = query(l,r);
}
}
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100005;
int n,m,t;
int a[N], pos[N], L[N], R[N], sum[N], add[N];
void modify(int l, int r, int d) {
int p = pos[l], q = pos[r];
if (p == q) {
for (int i = l; i <= r; ++i)
a[i] += d;
sum[p] += d * (r - l + 1);
return;
}
for (int i = p + 1; i <= q - 1; ++i)
add[i] += d;
for (int i = l; i <= R[p]; ++i)
a[i] += d;
sum[p] += d * (R[p] - l + 1);
for (int i = L[q]; i <= r; ++i)
a[i] += d;
sum[q] += d * (r - L[q] + 1);
}
LL ask(int l, int r) {
int p = pos[l], q = pos[r];
LL ans = 0;
if (p == q) {
for (int i = l; i <= r; ++i)
ans = (ans + a[i]);
ans = (ans + 1LL * add[p] * (r - l + 1));
return ans;
}
for (int i = p + 1; i <= q - 1; ++i)
ans = (ans + sum[i] + 1LL * add[i] * (R[i] - L[i] + 1));
for (int i = l; i <= R[p]; ++i)
ans = (ans + a[i]);
ans = (ans + 1LL * add[p] * (R[p] - l + 1));
for (int i = L[q]; i <= r; ++i)
ans = (ans + a[i]);
ans = (ans + 1LL * add[q] * (r - L[q] + 1));
return ans;
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; ++i)
scanf("%d", a + i);
t = sqrt(n);
for (int i = 1; i <= t; ++i)
L[i] = (i - 1) * t + 1, R[i] = i * t;
if (R[t] < n)
t++, L[t] = R[t - 1] + 1, R[t] = n;
for (int i = 1; i <= t; ++i)
for (int j = L[i]; j <= R[i]; ++j)
pos[j] = i, sum[i] += a[j];
for (int i = 1, opt, l, r, c; i <= m; ++i) {
scanf("%d", &opt);
if (opt==1)
{
scanf("%d%d%d",&l,&r,&c);
modify(l, r, c);
}
else
{
scanf("%d%d",&l,&r);
printf("%lld\n", ask(l, r));
}
}
}
树的直径
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=100010;
int n,m;
struct node{int v,dis,nxt;}E[maxn<<2];
int head[maxn],tot;
int dp[maxn],mxlen;
void add(int u,int v,int dis)
{
E[++tot].nxt=head[u];
E[tot].v=v; E[tot].dis=dis;
head[u]=tot;
}
void DP(int u,int pa)
{
dp[u]=0;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(v==pa) continue;
DP(v,u);
mxlen=max(mxlen,dp[u]+dp[v]+E[i].dis);
dp[u]=max(dp[u],dp[v]+E[i].dis);
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,0,sizeof(head));
tot=mxlen=0;
while(m--)
{
int u=read(),v=read(),dis=read();
char ss[5]; scanf("%s",&ss);
add(u,v,dis); add(v,u,dis);
}
DP(1,0);
printf("%d",mxlen);
}
return 0;
}
树链剖分 + 线段树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 100005;
int n,m,len,ind;
int head[MAXN],f[MAXN],top[MAXN],id[MAXN],size[MAXN],son[MAXN],dep[MAXN];
ll w[MAXN],a[MAXN];
struct Edge{
int to,next;
} e[MAXN * 2];
struct Tree{
int l,r;
ll sum,f;
} tree[MAXN * 4];
void add(int u,int v){
e[++len].to = v;
e[len].next = head[u];
head[u] = len;
}
void dfs1(int u,int fa,int d){
f[u] = fa;
size[u] = 1;
dep[u] = d;
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].to;
if(v == fa)
continue;
dfs1(v,u,d + 1);
size[u] += size[v];
if(size[v] > size[son[u]])
son[u] = v;
}
}
void dfs2(int u,int t){
top[u] = t;
id[u] = ++ind;
a[ind] = w[u];
if(!son[u])
return;
dfs2(son[u],t);
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].to;
if(v != f[u] && v != son[u])
dfs2(v,v);
}
}
void update(int k){
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
void down(int k){
tree[k * 2].sum += tree[k].f * (tree[k * 2].r - tree[k * 2].l + 1);
tree[k * 2 + 1].sum += tree[k].f * (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1);
tree[k * 2].f += tree[k].f;
tree[k * 2 + 1].f += tree[k].f;
tree[k].f = 0;
}
void build(int k,int l,int r){
tree[k].l = l;
tree[k].r = r;
if(l == r){
tree[k].sum = a[l];
return;
}
int mid = (l + r) / 2;
build(k * 2,l,mid);
build(k * 2 + 1,mid + 1,r);
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
void addInterval(int k,int l,int r,ll val){
if(tree[k].l >= l && tree[k].r <= r){
tree[k].f += val;
tree[k].sum += val * (tree[k].r - tree[k].l + 1);
return;
}
if(tree[k].f)
down(k);
int mid = (tree[k].l + tree[k].r) / 2;
if(l <= mid)
addInterval(k * 2,l,r,val);
if(r > mid)
addInterval(k * 2 + 1,l,r,val);
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
ll sumInterval(int k,int l,int r){
ll cnt = 0;
if(tree[k].l >= l && tree[k].r <= r)
return tree[k].sum;
if(tree[k].f)
down(k);
int mid = (tree[k].l + tree[k].r) / 2;
if(l <= mid)
cnt += sumInterval(k * 2,l,r);
if(r > mid)
cnt += sumInterval(k * 2 + 1,l,r);
return cnt;
}
void addPoint(int k,int x,ll val){
if(tree[k].l == tree[k].r){
tree[k].sum += val;
return;
}
if(tree[k].f)
down(k);
int mid = (tree[k].l + tree[k].r) / 2;
if(x <= mid)
addPoint(k * 2,x,val);
else
addPoint(k * 2 + 1,x,val);
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
ll sumTree(int x,int y){
int fx = top[x],fy = top[y];
ll ans = 0;
while(fx != fy){
if(dep[fx] >= dep[fy]){
ans += sumInterval(1,id[fx],id[x]);
x = f[fx];
fx = top[x];
}else{
ans += sumInterval(1,id[fy],id[y]);
y = f[fy];
fy = top[y];
}
}
if(id[x] <= id[y])
ans += sumInterval(1,id[x],id[y]);
else
ans += sumInterval(1,id[y],id[x]);
return ans;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
scanf("%lld",&w[i]);
for(int i = 1;i < n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
while(m--){
int op,x;
ll y;
scanf("%d%d",&op,&x);
if(op == 1){
scanf("%lld",&y);
addPoint(1,id[x],y);
}else if(op == 2){
scanf("%lld",&y);
addInterval(1,id[x],id[x] + size[x] - 1,y);
}else if(op == 3)
printf("%lld\n",sumTree(1,x));
}
return 0;
}