题解 orz最小生成树
查询[l,r]区间需要花费Cij 那么我们假设有n+1个状态分别表示前缀查询 那么我们对于查询[i,j]等价于(-1,j)连边 因为我们可以在Cij花费下 实现两个前缀状态的转移 又已知 我们知道所有前缀状态时 可以轻易找出每个位置的状态 所以只需要连边求MST即可
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=2e6+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
typedef struct node{
int u,v,k;
friend bool operator<(node aa,node bb){return aa.k<bb.k;}
}node;
node d[MAXN];
int f[2005];
int find1(int x){
if(x==f[x])return x;
return f[x]=find1(f[x]);
}
int main(){
int n=read();
int cnt=0,k;
inc(i,1,n){
inc(j,i,n){
d[++cnt]=(node){i,j+1,k=read()};
}
}
sort(d+1,d+cnt+1);
ll ans=0;
inc(i,1,n+1)f[i]=i;
inc(i,1,cnt){
int t1=find1(d[i].u);int t2=find1(d[i].v);
if(t1==t2)continue;
f[t1]=t2;ans+=d[i].k;
}
printf("%lld\n",ans);
}
3714: [PA2014]Kuglarz
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2224 Solved: 1029
[Submit][Status][Discuss]
Description
魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费c_ij元,魔术师就会告诉你杯子i,i+1,…,j底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?
Input
第一行一个整数n(1<=n<=2000)。
第i+1行(1<=i<=n)有n+1-i个整数,表示每一种询问所需的花费。其中c_ij(对区间[i,j]进行询问的费用,1<=i<=j<=n,1<=c_ij<=10^9)为第i+1行第j+1-i个数。
Output
输出一个整数,表示最少花费。
Sample Input
5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
Sample Output
7