题目链接:http://acm.buaa.edu.cn/problem/415/
题意:n个数,每次合并两个数,代价为这两个数的和。已知在第i次合并前有一些修改。每次合并时合并两个最小的数字。问最后的代价为多少?
思路:维护一个小根堆,记录每一个数在堆中的编号。
struct node
{
int id;
i64 cnt;
};
struct Event
{
int id,det;
Event(){}
Event(int _id,int _det)
{
id=_id;
det=_det;
}
};
const i64 INF=1e18;
const int MAX=10005;
node T[MAX];
int n,A,B,p[MAX];
vector<Event> V[MAX];
int C;
int Set[MAX];
void setInit(int n)
{
int i;
FOR1(i,n) Set[i]=i;
}
int setFind(int x)
{
if(Set[x]!=x) Set[x]=setFind(Set[x]);
return Set[x];
}
void down(int x)
{
int L,R,t;
node temp;
while(1)
{
L=x*2;
R=x*2+1;
if(L<=n&&(T[L].cnt<T[x].cnt||T[L].cnt==T[x].cnt&&T[L].id<T[x].id))
{
t=L;
}
else t=x;
if(R<=n&&(T[R].cnt<T[t].cnt||T[R].cnt==T[t].cnt&&T[R].id<T[t].id))
{
t=R;
}
if(t==x) return;
temp=T[x];
T[x]=T[t];
T[t]=temp;
p[T[t].id]=t;
p[T[x].id]=x;
x=t;
}
}
void up(int x)
{
int pre,t;
node temp;
while(1)
{
pre=x/2;
if(pre>=1&&(T[pre].cnt>T[x].cnt||T[pre].cnt==T[x].cnt&&T[pre].id>T[x].id))
{
t=pre;
}
else t=x;
if(t==x) return;
temp=T[t];
T[t]=T[x];
T[x]=temp;
p[T[t].id]=t;
p[T[x].id]=x;
x=t;
}
}
i64 deal(int x)
{
i64 i,ans=0,t;
node temp;
for(i=0;i<SZ(V[x]);i++)
{
t=setFind(V[x][i].id);
t=p[t];
T[t].cnt+=V[x][i].det;
if(V[x][i].det<0) up(t);
else down(t);
}
int preid=T[1].id;
ans+=T[1].cnt;
T[1]=T[n--];
down(1);
ans+=T[1].cnt;
T[1].cnt=ans;
if(preid>T[1].id) Set[preid]=T[1].id;
else
{
Set[T[1].id]=preid;
p[preid]=1;
T[1].id=preid;
}
down(1);
return ans;
}
int main()
{
for(scanf("%d",&C);C--;)
{
RD(n,A,B);
int i,j,x,y,z;
FOR1(i,n)
{
RD(T[i].cnt);
p[i]=T[i].id=i;
}
DOW1(i,n/2) down(i);
FOR1(i,n) CLR(V[i]);
FOR1(i,A)
{
RD(x,y,z);
V[x].pb(Event(y,-z));
}
FOR1(i,B)
{
RD(x,y,z);
V[x].pb(Event(y,z));
}
setInit(n);
i64 ans=0,tempN=n-1;
FOR1(i,tempN) ans+=deal(i);
PR(ans);
}
return 0;
}