题目还是自己看吧 - -!
看似图论,实际上是一个考察思维以及数据结构的题。
我们对于先前和向后的边分别进行统计。
对询问离线。
小边按照左端点从大到小排序。
1.对于向后的边,询问按照出发点从大到小排序。比如询问有
2 3
3 4
我们先对3 4进行计算。把向后的小边(3,5) ,(3,4) 用线段树维护,分别在线段树的位置4,5中插入用该边时可以优化的值。询问3 4时,我们发现出发点3以及后面的小边都加进了线段树中,直接询问线段树区间 [3,4]的最小值进行计算即可。注意一下可能加入了边之后比不加边更差的情况。
然后再对2 3进行计算,这次把小边(2,4)添加到线段树中,查询区间[2,4]的最小值即可。
2.对于向前的边,询问按照出发点从大到小排序。
同样跟1差不多,不过这次询问(x,y)时询问的是区间[1,y]。
具体可以看代码。
#include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; #define debug puts("here") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(unsigned i=0;i<vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) #define All(vec) vec.begin(),vec.end() #define MP make_pair #define PII pair<int,int> #define PQ priority_queue #define cmax(x,y) x = max(x,y) #define cmin(x,y) x = min(x,y) #define Clear(x) memset(x,0,sizeof(x)) #define lson rt<<1 #define rson rt<<1|1 /* #pragma comment(linker, "/STACK:1024000000,1024000000") int size = 256 << 20; // 256MB char *p = (char*)malloc(size) + size; __asm__("movl %0, %%esp " :: "r"(p) ); */ char IN; bool NEG; int OUT[15],top; inline void Int(int &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } inline void LL(ll &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } inline void out(ll x){ top = 0; while(x){ OUT[++top] = x%10; x /= 10; } if(!top)putchar('0'); while(top)putchar(char('0'+OUT[top--])); puts(""); } /******** program ********************/ const int MAXN = 200005; const ll INF = 1e15; ll ans[MAXN],sum[MAXN]; int val[MAXN],n,m; struct node{ int x,y,val; node(){} node(int _x,int _y,int _val):x(_x),y(_y),val(_val){} friend bool operator < (node a,node b){ return a.x>b.x; } }p[MAXN],a[MAXN],b[MAXN]; struct segTree{ int l,r; ll mx; inline int mid(){ return (l+r)>>1; } }tree[MAXN<<2]; void build(int l,int r,int rt){ tree[rt].l = l; tree[rt].r = r; tree[rt].mx = INF; if(l==r)return; int mid = tree[rt].mid(); build(l,mid,lson); build(mid+1,r,rson); } void modify(int pos,ll val,int rt){ if(tree[rt].l==tree[rt].r){ cmin(tree[rt].mx,val); return; } int mid = tree[rt].mid(); if(pos<=mid)modify(pos,val,lson); else modify(pos,val,rson); tree[rt].mx = min(tree[lson].mx,tree[rson].mx); } ll ask(int l,int r,int rt){ if(l<=tree[rt].l&&tree[rt].r<=r) return tree[rt].mx; int mid = tree[rt].mid(); if(r<=mid)return ask(l,r,lson); else if(l>mid)return ask(l,r,rson); else return min(ask(l,r,lson),ask(l,r,rson)); } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif while(~RD2(n,m)){ REP(i,2,n){ Int(val[i]); sum[i] = sum[i-1]+val[i]; } rep1(i,m){ Int(p[i].x); Int(p[i].y); Int(p[i].val); } int qq; Int(qq); int na = 0 , nb = 0 , x , y; rep1(i,qq){ Int(x); Int(y); if(x>y)b[++nb] = node(x,y,i); else a[++na] = node(x,y,i); } sort(a+1,a+na+1); sort(p+1,p+m+1); int pos = 1; build(1,n,1); rep1(i,na){ while(pos<=m&&p[pos].x>=a[i].x){ x = p[pos].x , y = p[pos].y; if(x<=y) modify(y,p[pos].val-(sum[y]-sum[x]),1 ); pos ++; } ll tmp = ask(a[i].x,a[i].y,1); if(tmp>0)tmp = 0; ans[ a[i].val ] = sum[ a[i].y ]-sum[ a[i].x ]+tmp; } sort(b+1,b+nb+1); pos = 1; build(1,n,1); rep1(i,nb){ while( pos<=m&&p[pos].x>=b[i].x ){ x = p[pos].x , y = p[pos].y; if(x>=y) modify(y,sum[x]-sum[y]+p[pos].val,1); pos ++; } ans[ b[i].val ] = ask(1,b[i].y,1)-(sum[b[i].x]-sum[b[i].y]); } rep1(i,qq) out(ans[i]); } return 0; }