Description
Cedyks是九条可怜的好朋友(可能这场比赛公开以后就不是了),也是这题的主人公。
Cedyks是一个富有的男孩子。他住在著名的ThePLace(宫殿)中。
Cedyks是一个努力的男孩子。他每天都做着不一样的题来锻炼他的The SaLt(灵魂)。
这天,他打算在他的宫殿外围修筑一道城墙,城墙上有n座瞭望塔。
你可以把城墙看做一条线段,瞭望塔是线段上的n个点,其中1和n分别为城墙的两个端点。
其中第i座瞭望塔和第i+1座瞭望塔的距离为wi,他们之间的道路是双向的。
城墙很快就修建好了,现在Cedyks开始计划修筑他的宫殿到城墙的道路。 因为这题的题目名称,
Cedyks打算用他的宫殿到每一个瞭望塔的最短道路之和来衡量一个修建计划。
现在Cedyks手上有m个设计方案,第k个设计方案会在宫殿和瞭望塔之间修建Tk条双向道路, 第i条道路连接着瞭望塔ai,长度为Li。
计算到每一个瞭望塔的最短路之和是一个繁重的工程,本来Cedyks想用广为流传的SPFA算法
来求解,但是因为他的butter(缓冲区)实在是太小了,他只能转而用原始的贝尔福特曼算法 来计算,算法的流程大概如下:
1:定义宫殿是0号点,第i个瞭望塔是i号点,双向边(ui,vi,Li)为一条连接ui和vi的双向道路。
令d为距离数组,最开始d0=0,di=10^18(i∈[1,n])。 2:令辅助数组c=d。依次对于每一条边(ui,vi,wi)进行增广,
cui=min(cui,dvi+wi), cvi=min(cvi,dui+wi)。
3:令t为c和d中不一样的位置个数,即令S={i|ci!=di},则t=S。若t=0,说明d
就是最终的最短路,算法结束。否则令d=c,回到第二步。 因为需要计算的设计方案实在是太多了,所以Cedyks雇佣了一些人来帮他进行计算。
为了避免这些人用捏造出来的数据偷懒,他定义一个设计方案的校验值为在这个方案
上运行贝尔福特曼算法每一次进入第三步t的和。他会让好几个雇佣来的人计算同样 的设计方案,并比对每一个人给出的校验值。
你是Cedyks雇佣来的苦力之一,聪明的你发现在这个情形下计算最短路的长度的和
是一件非常简单的事情。但是寄人篱下不得不低头,你不得不再计算出每一个方案 的校验值来交差。
Input
第一行输入两个整数n,m,表示瞭望塔个数和设计方案个数。 接下来一行n-1个数wi,表示瞭望塔i和i+1之间道路的长度。
接下来m行,每行描述一个设计方案。 第一个整数K表示设计方案中的道路数量, 接下来K个数对(ai,Li)为一条宫殿到瞭望塔的边。 1 <=
wi, li <= 109, 1 <= ∑ K <= 2 × 10^5 N,M<=2*10^5
Output
对于每一个设计方案,输出一行一个整数表示校验值。
Sample Input
5 5
2 3 1 4
1 2 2
2 1 1 4 10
3 1 1 3 1 5 1
3 1 10 2 100 5 1
5 1 1 2 1 3 1 4 1 5 1
Sample Output
5
8
5
8
5
题解
如同一个sb
先是一个性质
这张图最后是被某个点更新的点一定是连续一段的
开始想用单调栈维护最终每个点更新的是哪一段,然后在这个基础上算答案
然后发现假了…
其实不妨把这个性质转一下
每个点能更新到的点同样也是连续一段的,这里的更新并不保证最后这个点不被其他点更新
这里我们的意思是让这个点到两个端点这一段路径,是否有可能成为某一段时间的最短路那么这样的话,答案就很方便计算了
就是∑ri−li+1\sum r_i-l_i+1∑ri−li+1
推一下柿子然后用两个ST表维护最小值
注意一个点如果能被他两边的点同时更新,那么我们取左边那个点更新
还是那个道理
很多时候,问题并不能一步解决
把东西转换一下,就变得显而易见了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=200005;
LL prefix[MAXN];
int n,m,T;
LL mn[20][MAXN][2],s1[MAXN],s2[MAXN],Log[MAXN],bin[25];
int is[MAXN],tim;
void init(int ln)
{
for(int i=1;i<=ln;i++)mn[0][i][0]=s1[i],mn[0][i][1]=s2[i];
for(int i=1;bin[i]<=ln;i++)
for(int x=1;x+bin[i]-1<=ln;x++)
{
mn[i][x][0]=min(mn[i-1][x][0],mn[i-1][x+bin[i-1]][0]);
mn[i][x][1]=min(mn[i-1][x][1],mn[i-1][x+bin[i-1]][1]);
}
}
LL getmn(int l,int r,int o)
{
int K=Log[r-l+1];
return min(mn[K][l][o],mn[K][r-bin[K]+1][o]);
}
struct edge{int x,c;}w[MAXN];
bool cmp(edge n1,edge n2){return n1.x<n2.x;}
int getpos(int u,int o)
{
int l=1,r=T,re=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(o==0)//找大于等于的
{
if(w[mid].x>=u)re=mid,r=mid-1;
else l=mid+1;
}
else//找小于等于的
{
if(w[mid].x<=u)re=mid,l=mid+1;
else r=mid-1;
}
}
return re;
}
bool check1(int u1,int u2,LL c)
{
int ls=max(1,u1-(u2-u1)),rs=u2-1;
int p1=getpos(ls,0),p2=getpos(rs,1),p3=getpos(u1,1);
if(p2==-1)return true;
bool re=true;
if(p1<=p3)
{
LL di=getmn(p1,p3,0);
if(prefix[u1]+di<=c)re=false;
}
p3=getpos(u1,0);
if(p3<=p2)
{
LL di=getmn(p3,p2,1);
if(-prefix[u1]+di<=c)re=false;
}
return re;
}
int getl(int u,int c)
{
int l=1,r=u,re=u;
while(l<=r)
{
int mid=(l+r)/2;
if(check1(mid,u,prefix[u]-prefix[mid]+c))re=mid,r=mid-1;
else l=mid+1;
}
return re;
}
bool check2(int u1,int u2,LL c)
{
int ls=u2+1,rs=min(n,u1+u1-u2);
int p1=getpos(ls,0),p2=getpos(rs,1),p3=getpos(u1,1);
if(p1==-1)return true;
bool re=true;
if(p1<=p3)
{
LL di=getmn(p1,p3,0);
if(prefix[u1]+di<=c)re=false;
}
p3=getpos(u1,0);
if(p3<=p2&&p3!=-1)
{
LL di=getmn(p3,p2,1);
if(-prefix[u1]+di<c)re=false;
else if(-prefix[u1]+di==c)
{
if(p3<p2)
{
di=getmn(p3,p2-1,1);
if(-prefix[u1]+di<=c)re=false;
}
if(u1+u1-u2<=n&&is[u1+u1-u2]==tim&&prefix[w[p2].x]-prefix[u1]+w[p2].c==c)re&=1;
else re=false;
}
}
return re;
}
int getr(int u,int c)
{
int l=u,r=n,re=u;
while(l<=r)
{
int mid=(l+r)/2;
if(check2(mid,u,prefix[mid]-prefix[u]+c))re=mid,l=mid+1;
else r=mid-1;
}
return re;
}
void solve()
{
T=read();tim++;
for(int i=1;i<=T;i++)w[i].x=read(),w[i].c=read(),is[w[i].x]=tim;
sort(w+1,w+1+T,cmp);
for(int i=1;i<=T;i++)s1[i]=w[i].c-prefix[w[i].x],s2[i]=w[i].c+prefix[w[i].x];
init(T);LL ans=0;
for(int i=1;i<=T;i++)
{
int l=getl(w[i].x,w[i].c);
int r=getr(w[i].x,w[i].c);
ans+=r-l+1;
}
pr2(ans);
}
int main()
{
bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
Log[1]=0;for(int i=2;i<MAXN;i++)Log[i]=Log[i>>1]+1;
n=read();m=read();
for(int i=2;i<=n;i++)prefix[i]=prefix[i-1]+read();
while(m--)solve();
return 0;
}