Time Limits: 2000 ms
Memory Limits: 262144 KB
输入文件为 s p l i t . i n split.in split.in。
第一行 包含 一个正整数 T,表示有T组测试数据 。接下来 依次是 T组测试数 据。
每组测试数 据的第一行包含个正整数N。
第二行包含 N个 0、1、2之一 的整数,依次 表示点 1到点 N的颜色。其中0表示黑色, 1表示白色, 2表示灰色。
接下来 N-1行 ,每行为三个整数 ui、vi、ci,表示 一条权值等于 ci的边 ( u i , v i ) (ui, vi) (ui,vi)。
输出文件为 s p l i t . o u t split.out split.out。
输出 T行 ,每一个整数, 依次 表示 每组测试数据 的答案。
1
5
0 1 1 1 0
1 2 5
1 3 3
5 2 5
2 4 16
10
【样例解释】
花费 10 的代价删去 边(1, 2)和边(2, 5)。
对于 10% 的数据: 1 ≤ N ≤ 10。
对于 30% 的数据: 1 ≤ N ≤ 50 0。
对于 60% 的数据: 1 ≤ N ≤ 50 000 。
对于 100% 的数据: 1 ≤ N ≤ 300 000 ,1 ≤ T ≤ 5,0 ≤ ci ≤ 10^9。
Time Limits: 1000 ms
Memory Limits: 262144 KB
输入文件为 s e c r e t . i n secret.in secret.in:
第一行 包含一 个正整数 T,表示有 T组测试数据。接下来 依次是 T组测试数 据。
每组测试数 据的第一行包含两个整N、M。
第二行包含 N - 1个正整数,依次表示 A1,A2, …,AN-1。
接下来 M行,每 行为三个 整数: ui、vi、ci,表示一条连接城市ui和城市 vi的路程等于 ci的高速公路。
输出文件为 s e c r e t . o u t secret.out secret.out。
输出 T行, 依次 表示 每组测试数据 的答案 。若最优 方案 唯一 则输出 ”Yes”和 最小 代价 ,否则 输出 ”No ”和最小 代价 。字符串 和整数 之间 请用一个 空格 隔开 。
3
3 3
2 4
1 3 23
3 2 12
2 1 11
4 4
3 2 2
1 2 1
2 3 1
3 4 1
4 1 1
3 4
3 2
1 2 1
2 3 2
2 3 19
3 1 4
Yes 4
Yes 3
No 2
【样例解释】
第 1组测试数据: 最优 方案 是在城市 1设立 两个 检查点 。
第 2组测试数据: 最优 方案 是城市 1的高速公路 (1, 4 )的出入口设立 检查点。
第 3组测试数据: 最优 方案 是在城市 2设立 一个 检查点 ,不过 既可以 设置 在 高速公路 (1, 2)的出入 口,也可以 设置 在高速公路 (2, 3)的出入口 。
对于 10% 的数据: 2 ≤ N ≤ 10 , 1 ≤ M ≤ 20。
另有 40% 的数据: 最优 方案 是唯一 的。
对于 10 0% 的数据: 2 ≤ N ≤ 400, 1 ≤ M ≤ 4 00 0,1 ≤ T ≤ 5,1 ≤ Ai, c ≤ 10^9。无向图可能有重边。
Time Limits: 3000 ms
Memory Limits: 524288 KB
对于一个整数序列,查询区间第k大数可以在O(logN)的时间内轻松完成。现在我们对这个问题进行推广。
考虑带重复数的集合(multiset)。定义在该类集合上的并操作“+”为两个集合的所有数不剔除重复得到的结果。比如,若A={1,2,2,3},B={2,3,4,4},则C={1,2,2,2,3,3,4,4}。
对于一个给定序列A[1…N],定义A[x…y]为包含y-x+1个元素的集合{A[x],A[x+1],…,A[y]}。现在,给定整数序列A,你需要回答很多询问,其中第i个询问要求集合A[x[i,1]…y[i,1]]+A[x[i,2]…y[i,2]]+…+A[x[i,ki]…y[i,ki]]中第pi小的元素。
输入的第一行包含两个整数N和M,分别表示整数序列的长度和询问的个数。
第二行N个整数给出整数序列A。
第3到第M+2行给出了所有的询问。第i+2行前两个整数为ki和pi,接下来2ki个整数给出x[i, 1], y[i, 1], x[i,2], …, x[i, ki], y[i, ki]。这些数按照题目中的定义描述了第i个询问。
对于每一个询问,输出相应的结果,即从小到大排序后的第pi个元素。
8 3
1 2 3 1 2 3 1 2
2 4 1 4 3 7
2 4 1 3 6 8
5 31 1 8 1 8 1 8 1 8 1 8
1
2
3
第1、2个测试数据满足N ≤ 1 000,M ≤ 1 000。
第3、4个测试数据满足ki = 1。
所有的测试点满足N ≤ 200 000,M ≤ 200 000,0 ≤ A[i] ≤ 1 000 000,ki ≤ 5。
保证 1 ≤ x [ i , j ] ≤ N , 1 ≤ y [ i , j ] ≤ N , 1 ≤ p i ≤ ∑ j ( y [ i , j ] − x [ i , j ] + 1 ) 1 \leq x[i,j] \leq N, 1 \leq y[i, j] \leq N, 1 \leq pi \leq \sum_j(y[i, j] - x[i, j] + 1) 1≤x[i,j]≤N,1≤y[i,j]≤N,1≤pi≤∑j(y[i,j]−x[i,j]+1)。
【样例说明】
第一个询问集合为 1 , 2 , 3 , 1 , 3 , 1 , 2 , 3 , 1 {1,2,3,1,3,1,2,3,1} 1,2,3,1,3,1,2,3,1,第4小元素为1。
今天的题目难度适中,数据终于不水了。
得分:0+0+100=100
读了一遍题,感觉T3最水,裸的主席树,不切都不好意思了,于是开始刚。。。
先把原数列离散化,建树时动态开点(详见线段树详解),其中第 i 棵权值线段树储存 [ 1.. i ] [1..i] [1..i]中每一个数出现的次数。询问时把第y棵线段树减去第 x − 1 x-1 x−1棵线段树,再查询。
10点左右,程序打完了,交了上去,不料跑了2min+都没有跑完。
完美卡OJヾ(⌐■_■)ノ♕!
后来发现,可以一边减一边查询,因为我们只需要一条从根到底的路径,而相减会得出许多无用的路径。
然后就AC了。
接着打了1个多小时的T2暴力,却连SPFA都没有调出来,完美爆〇(后来发现是因为我建边时有下标为0的边,而遍历一个点连接的边时把这条边判掉了)
不妨把无根树转化成以1为根的树。
设 F i F_i Fi表示 i 所在的子树含有0个黑色节点的最优解, G i G_i Gi表示 i 所在的子树含有0个白点的最优解, H i H_i Hi表示 i 所在的子树含有1个白色节点的最优解。
然后从底到根DP。
这样子做似乎就可以了,但是
题目中有一句话:
对于 100% 的数据: 1 ≤ N ≤ 300 000
于是@#%#¥%@%@#*)¥~#¥@……
其实解决方法也很容易:BFS一遍,然后把队列反过来就可以了。
首先可以发现不在最短路上的点都是没有用的。
于是只保留那些可以更新某个点的最短路的边。
然后答案要求用最小的费用使1~n不连通,这就是最小割,即最大流。
于是答案就出来了,现在的关键就是判断它是否唯一。
有一个不显然的性质:
有向边 ( u , v ) (u,v) (u,v)必定出现在任意最小割中当且仅当残量网络中存在S到u的路径和v到T的路径(此处的路径指的是由没有满流的弧组成的路径)。
那么如果出现在任意最小割中的边的原始容量之和不等于答案,方案就不唯一。
这里可以从1和n分别做一次DFS,最后判断一下就可以了。
特殊地,当一条边的 a u = a v a_u=a_v au=av时,答案不唯一。
#include
using namespace std;
#define ll long long
#define N 300005
#define M 1000005
#define inf 300000000000000
int fir[N],end[N<<1],nex[N<<1],a[N],data[N],fa[N];
ll f[N],g[N],h[N],cost[N<<1],temp;char ch;
inline ll min(ll x,ll y){return x<y?x:y;}
inline ll min(ll x,ll y,ll z){return x<z&&x<y?x:min(y,z);}
inline char gc()
{
static char buf[M],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
int main()
{
int t,n,k,i,l,x,y,z,m,head,tail;
read(t);
while(t--)
{
read(n),m=0;
for(i=1;i<=n;i++) read(a[i]),fir[i]=0;
for(i=1;i<n;i++)
{
read(x),read(y),read(z);
end[++m]=y,cost[m]=z,nex[m]=fir[x],fir[x]=m;
end[++m]=x,cost[m]=z,nex[m]=fir[y],fir[y]=m;
}
head=0,tail=1,data[1]=1;
while(head<tail)
{
k=data[++head];
for(i=fir[k];i;i=nex[i]) if(end[i]!=fa[k])
{
fa[end[i]]=k;
data[++tail]=end[i];
}
}
for(l=n;l;l--)
{
k=data[l];
if(!a[k])//black
{
f[k]=h[k]=inf,g[k]=0;
for(i=fir[k];i;i=nex[i])
if(end[i]!=fa[k])
g[k]+=min(f[end[i]]+cost[i],g[end[i]],h[end[i]]+cost[i]);
for(i=fir[k];i;i=nex[i])
if(end[i]!=fa[k])
h[k]=min(h[k],h[end[i]]+g[k]-min(f[end[i]]+cost[i],g[end[i]],h[end[i]]+cost[i]));
}
else if(a[k]<2)//white
{
f[k]=h[k]=0,g[k]=inf;
for(i=fir[k];i;i=nex[i]) if(end[i]!=fa[k])
{
f[k]+=min(f[end[i]],g[end[i]]+cost[i],h[end[i]]+cost[i]);
h[k]+=min(f[end[i]]+cost[i],g[end[i]],h[end[i]]+cost[i]);
}
}
else//gray
{
h[k]=inf,f[k]=g[k]=0;
for(i=fir[k];i;i=nex[i]) if(end[i]!=fa[k])
{
f[k]+=min(f[end[i]],g[end[i]]+cost[i],h[end[i]]+cost[i]);
g[k]+=min(f[end[i]]+cost[i],g[end[i]],h[end[i]]+cost[i]);
}
for(i=fir[k];i;i=nex[i])
if(end[i]!=fa[k])
h[k]=min(h[k],h[end[i]]+g[k]-min(f[end[i]]+cost[i],g[end[i]],h[end[i]]+cost[i]));
}
}
printf("%lld\n",min(f[1],g[1],h[1]));
}
return 0;
}
#include
#include
using namespace std;
#define ll long long
#define inf 400000000000
#define M 8005
#define N 405
struct EDGE{ll end,lenth,next;}edge[M];
ll n,m,s,sum,a[N],fir[N],lenth[M],end[M],nex[M],dis[N],GAP[N],data[200000];
bool exist[N],b[N],bz[N];
inline ll min(ll x,ll y){return x<y?x:y;}
inline void inc(ll x,ll y,ll z)
{
end[++s]=y,lenth[s]=z,nex[s]=fir[x],fir[x]=s;
end[++s]=x,lenth[s]=z,nex[s]=fir[y],fir[y]=s;
}
inline void add(ll x,ll y,ll z)
{
edge[++s]=(EDGE){y,z,fir[x]},fir[x]=s;
edge[++s]=(EDGE){x,0,fir[y]},fir[y]=s;
}
inline void spfa()
{
int i,head=0,tail=1,u,v;
for(i=2;i<=n;i++) dis[i]=inf,exist[i]=1;
data[1]=1,dis[1]=0;
while(head<tail)
{
u=data[++head],exist[u]=1;
for(i=fir[u];i;i=nex[i])
{
v=end[i];
if(dis[v]>dis[u]+lenth[i])
{
dis[v]=dis[u]+lenth[i];
if(exist[v]) exist[v]=0,data[++tail]=v;
}
}
}
}
ll sap(ll k,ll flow)
{
if(k==n) return flow;
ll i,j,t,have=flow;
for(i=fir[k];i;i=edge[i].next)
if(edge[i].lenth&&dis[k]==dis[j=edge[i].end]+1)
{
t=sap(edge[i].end,min(edge[i].lenth,have));
have-=t,edge[i].lenth-=t,edge[i^1].lenth+=t;
if(!have) return flow;
}
if(!(--GAP[dis[k]])) GAP[1]=n;
++GAP[++dis[k]];
return flow-have;
}
void dfs1(ll k)
{
b[k]=0;
for(ll i=fir[k];i;i=edge[i].next)
if(edge[i].lenth&&b[edge[i].end])
dfs1(edge[i].end);
}
void dfs2(ll k)
{
bz[k]=0;
for(ll i=fir[k];i;i=edge[i].next)
if(edge[i^1].lenth&&bz[edge[i].end])
dfs2(edge[i].end);
}
int main()
{
ll task,i,j,x,y,z,ans=0;
scanf("%lld",&task);
while(task--)
{
scanf("%lld%lld",&n,&m);
for(i=1;i<n;i++) scanf("%lld",a+i),fir[i]=0;
a[n]=inf,fir[n]=0,s=1;
for(i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
inc(x,y,z);
}
spfa();
memset(fir,0,sizeof(fir));
for(i=s,s=1;i>1;i--)
if(dis[end[i]]+lenth[i]==dis[end[i^1]])
add(end[i],end[i^1],min(a[end[i]],a[end[i^1]]));
memset(dis,0,sizeof(dis));
memset(GAP,0,sizeof(GAP)),ans=0;
while(dis[1]<n) ans+=sap(1,inf);
memset(b,1,sizeof(b));
memset(bz,1,sizeof(bz));
dfs1(1),dfs2(n);
for(sum=0,i=2;i<=s;i+=2)
if((!b[edge[i^1].end])&&(!bz[edge[i].end]))
{
if(a[edge[i^1].end]==a[edge[i].end])
{sum=0;break;}
sum+=min(a[edge[i^1].end],a[edge[i].end]);
}
if(sum==ans) printf("Yes %lld\n",ans);
else printf("No %lld\n",ans);
}
return 0;
}
#include
#include
using namespace std;
#define M 7200005
#define N 200005
struct number
{
int num,id;
}rec[N];
struct node
{
int sum,lson,rson;
node(){sum=lson=rson=0;}
}a[M];
int cnt,num[N],b[N],x[10],y[10];char ch;
inline char gc()
{
static char buf[M],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
bool cmp(number x,number y){return x.num<y.num;}
void add(int x,int y,int l,int r,int num)
{
a[x].sum=a[y].sum+1;
if(l==r) return;
int mid=l+r>>1;
if(num<=mid)
{
a[x].rson=a[y].rson,a[x].lson=++cnt;
add(a[x].lson,a[y].lson,l,mid,num);
}
else
{
a[x].lson=a[y].lson,a[x].rson=++cnt;
add(a[x].rson,a[y].rson,mid+1,r,num);
}
}
int query(int k,int l,int r,int num)
{
if(l==r) return l;
int mid=l+r>>1,i,s=0;
for(i=1;i<=k;i++) s+=a[a[y[i]].lson].sum-a[a[x[i]].lson].sum;
if(s>=num)
{
for(i=1;i<=k;i++) x[i]=a[x[i]].lson,y[i]=a[y[i]].lson;
query(k,l,mid,num);
}
else
{
for(i=1;i<=k;i++) x[i]=a[x[i]].rson,y[i]=a[y[i]].rson;
query(k,mid+1,r,num-s);
}
}
int main()
{
int n,m,i,j,k,t;
read(n),read(m),cnt=n+1;
for(i=1;i<=n;i++) read(rec[i].num),rec[i].id=i;
sort(rec+1,rec+n+1,cmp),rec[0].num=-1;
for(i=1,j=0;i<=n;i++)
{
if(rec[i].num>rec[i-1].num) b[++j]=rec[i].num;
num[rec[i].id]=j;
}
for(i=1;i<=n;i++) add(i,i-1,1,n,num[i]);
while(m--)
{
read(j),read(k);
for(i=1;i<=j;i++)
{
read(x[i]),read(y[i]),x[i]--;
if(x[i]>=y[i]) i--,j--;
}
printf("%d\n",b[query(j,1,n,k)]);
}
return 0;
}