BZOJ 4777

Description

Farmer John has recently been experimenting with cultivating different types of grass on his farm, r
ealizing that different types of cows like different types of grass. However, he must be careful to 
ensure that different types of grass are planted sufficiently far away from each-other, in order to 
prevent them from being inextricably mixed.FJ's farm consists of Nfields (1≤N≤200,000), where M pa
irs of fields are connected by bi-directional pathways (1≤M≤200,000). Using these pathways, it is 
possible to walk from any field to any other field. Each pathway has an integer length in the range 
1…1,000,000. Any pair of fields will be linked by at most one direct pathway.In each field, FJ init
ially plants one of Ktypes of grass (1≤K≤N). Over time, however, he might decide to switch the gra
ss in some field to a different type. He calls this an "update" operation. He might perform several 
updates over the course of time, which are all cumulative in nature.After each update, FJ would like
 to know the length of the shortest path between two fields having different grass types. That is, a
mong all pairs of fields having different grass types, he wants to know which two are closest. Ideal
ly, this number is large, so he can prevent grass of one type from mixing with grass of another type
. It is guaranteed that the farm will always have at least two fields with different grass types.In 
30 percent of the input cases, each field will be directly connected to at most 10 pathways.
给定一张带权无向图,每个点有一个颜色,每次改变一个点的颜色,要求你在操作后输出这个图中最近异色点对之
间的距离最近异色点对定义为:一对点颜色不同,且距离最小

Input

The first line of input contains four integers, N, M, K, and Q, where Q is the number of updates (1
≤Q≤200,000). The next M lines describe the paths; each one contains three integers A, B, and L, in
dicating a path from field A to field B (both integers in the range 1…N) of length L. The next line
 indicates the initial type of grass growing in each field (N integers in the range 1…K). Finally, 
the last Q lines each describe an update, specified by two integers A and B, where the grass in fiel
d A is to be updated to type B

Output

For each update, print the length of the shortest path between two fields with different types of grass
after the update is applied.

Sample Input

3 2 3 4
1 2 3
2 3 1
1 1 2
3 3
2 3
1 2
2 2

Sample Output

1
3
3
1

这题可真TM调的我一逼。。校内测试时用sort水了60正解需要知道两个性质。。

性质1:最后解一定是一条边。因为如果有3个点A,B,C且A,C通过B相连,且A,C,颜色不同,那么B和A,C中一个点颜色一定不同(显然)然而w(A,C)>w(B,C)||w(A,B)

性质2:最后解一定在最小生成树里

假如答案边不在最小生成树上,那么最小生成树上两点之间的路径上一定能找到一条合法的答案边,且权值不会比它大

有了性质后就可以先Kruskal最小生成树然后再对每一个节点建树套树或树套set

再维护一个Ans的平衡树或set

还有这题zz到卡内存到丧心病狂。。自行体会一下吧。

树套树:

#define MAXN 205005
#define inf (0x3f3f3f3f)
 
#include <iostream>
#include <queue>
#include <cstring>
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
int first[MAXN],e=1,n,m,k,q,val[MAXN],cost[MAXN],f[MAXN],last[MAXN];
 
 
template<typename _t>
inline _t read(){
    _t x=0;
    int f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return (_t)x*f;
}
 
struct edge{
    int u,v,next,w;
    bool operator < (const edge &a)const{
        return w<a.w;
    }
}a[MAXN<<1],b[MAXN<<1];
 
void push(int u,int v,int w){
    a[e].u=u;
    a[e].v=v;
    a[e].w=w;
    a[e].next=first[u];
    first[u]=e++;
}
 
int fa[MAXN];
 
int find(int x){
    if(fa[x]!=x)    
        fa[x]=find(fa[x]);
    return fa[x];
}
 
void Bfs(){
    bool vis[MAXN];
    memset(vis,0,sizeof vis);
    queue<int>q;
    q.push(1);
    vis[1]=1;
    while(!q.empty()){
        int k = q.front();
        q.pop();
        for(int i=first[k];i;i=a[i].next){
            if(!vis[a[i].v]){
                f[a[i].v]=k;
                cost[a[i].v]=a[i].w;
                vis[a[i].v]=1;
                q.push(a[i].v);
            }
        }
    }
}
 
void Kr(){
    sort(b+1,b+1+m);
    int cnt = 0;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int u = find(b[i].u),v=find(b[i].v);
        if(u==v)continue;
        fa[u]=v;
        push(b[i].u,b[i].v,b[i].w);
        push(b[i].v,b[i].u,b[i].w);
        if(cnt==n-1)break;
    }
    Bfs();
}
 
struct Treap_node{
    int v,r;
    Treap_node *ch[2];
     
    Treap_node(){}
    Treap_node(int x){
        v = x;r=rand();
        ch[0]=ch[1]=NULL;
    }
    void *operator new (size_t);
 
    void operator delete (void* p);
 
    int cmp(int x)const{
        if(x==v)return -1;
        return x<v?0:1;
    }
}*C,*mempool,*Ans;
 
vector<Treap_node*>Stack;
 
void* Treap_node :: operator new (size_t){
    Treap_node *p;
    if(!Stack.empty()){
        p = Stack.back();
        Stack.pop_back();
    }
    else{
        if(C==mempool){
            C=new Treap_node[1<<15];
            mempool = C+(1<<15);
        }
        p=C++;
    }
    return p;
}
 
void Treap_node :: operator delete (void* p){
    Stack.push_back((Treap_node*)p);
}
 
void rotate (Treap_node *&o,int d){
    Treap_node *p=o->ch[d^1];
    o->ch[d^1]=p->ch[d];
    p->ch[d]=o;
    o=p;
}
 
void Treap_insert(Treap_node *&o,int x){
    if(!o)o=new Treap_node(x);
    else{
        int d = x<o->v ? 0:1;
        Treap_insert(o->ch[d],x);
        if(o->ch[d]->r > o->r)rotate(o,d^1);
    }
}
 
void Treap_erase(Treap_node *&o,int x){
    int d = o->cmp(x);
    if(d==-1){
        Treap_node *tmp = o;
        if(o->ch[0]!=NULL&&o->ch[1]!=NULL){
            int k = o->ch[0]->r > o->ch[1]->r ? 1:0;
            rotate(o,k);
            Treap_erase(o->ch[k],x);
        }
        else{
            if(o->ch[1]==NULL)o=o->ch[0];
            else o = o->ch[1];
            delete tmp;
            tmp = NULL;
        }
    }
    else Treap_erase(o->ch[d],x);
}
 
int Treap_Query(Treap_node *x){
    int tot = inf;
    while(x){
        tot=min(tot,x->v);
        x=x->ch[0];
    }
    return tot;
}
 
struct Tree{
    Tree *ls,*rs;
    Treap_node *v;
    int min_x;
     
    Tree()  { ls=rs=NULL,v=NULL,min_x=inf; }
     
    void Push_up(){
        #define MIN(x) ((x)?((x)->min_x):inf)
        min_x=min(MIN(ls),MIN(rs));
    }
 
    void* operator new (size_t);
 
    void operator delete(void* p);
}*root[MAXN],*S,*T;
 
vector<Tree*>bin;
 
void* Tree :: operator new(size_t size){
    Tree *o;
    if(!bin.empty()){
        o=bin.back();
        bin.pop_back();
    }
    else{
        if(S==T){
            S=new Tree[1<<15];
            T=S+(1<<15);
        }
        o = S++;
    }
    o->ls=o->rs=NULL;
    o->v=NULL;
    o->min_x=inf;
    return o;
}
 
void Tree :: operator delete (void* p){
    bin.push_back((Tree*)p);
}
 
void insert(Tree *&o,int l,int r,int x,int va){
    if(!o)o = new Tree;
    if(l==r){
        Treap_insert(o->v,va);
        o->min_x=Treap_Query(o->v);
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)insert(o->ls,l,mid,x,va);
    else insert(o->rs,mid+1,r,x,va);
    o->Push_up();
}
 
void erase(Tree *&o,int l,int r,int x,int va){
    if(l==r){
        Treap_erase(o->v,va);
        o->min_x=Treap_Query(o->v);
        return;
    }
    int mid = l+r>> 1;
    if(x<=mid)erase(o->ls,l,mid,x,va);
    else erase(o->rs,mid+1,r,x,va);
    o->Push_up();
    if(o->min_x==inf){
        delete o;
        o=NULL;
    }
}
 
int query(Tree *o,int l,int r,int x,int y){
    if(!o)return inf;
    if(x<=l&&r<=y)return o->min_x;
    int mid = l+r>>1,ans=inf;
    if(x<=mid)ans=min(ans,query(o->ls,l,mid,x,y));
    if(mid<y)ans=min(ans,query(o->rs,mid+1,r,x,y));
    return ans;
}
 
int Query(int x){
    int ans = inf;
    if(val[x]!=1)ans=min(ans,query(root[x],1,k,1,val[x]-1));
    if(val[x]!=k)ans=min(ans,query(root[x],1,k,val[x]+1,k));
    return ans;
}
 
int main(){
    bin.clear();
    n=read<int>();
    m=read<int>();
    k=read<int>();
    q=read<int>();
    for(int i=1;i<=m;i++)scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w);
    for(int i=1;i<=n;i++)scanf("%d",&val[i]);Kr();
    for(int i=2;i<=n;i++)insert(root[f[i]],1,k,val[i],cost[i]);
    for(int i=1;i<=n;i++)Treap_insert(Ans,last[i]=Query(i));
    while(q--){
        int pos=read<int>(),w=read<int>();
         
        if(f[pos])erase(root[f[pos]],1,k,val[pos],cost[pos]);
         
        val[pos]=w;
 
        if(f[pos])insert(root[f[pos]],1,k,val[pos],cost[pos]);
 
        Treap_erase(Ans,last[pos]);
        Treap_insert(Ans,last[pos]=Query(pos));
 
        if(f[pos]){
            Treap_erase(Ans,last[f[pos]]);
            Treap_insert(Ans,last[f[pos]]=Query(f[pos]));
        }
 
        printf("%d\n",Treap_Query(Ans));
    }
}
树+Set

#define MAXN 205005
#define inf (0x3f3f3f3f)
 
#include <iostream>
#include <set>
#include <queue>
#include <cstring>
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
int first[MAXN],e=1,n,m,k,q,val[MAXN],cost[MAXN],f[MAXN],last[MAXN];
multiset<int>Ans;
multiset<int>::iterator it;
 
 
template<typename _t>
inline _t read(){
    _t x=0;
    int f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return (_t)x*f;
}
 
struct edge{
    int u,v,next,w;
    bool operator < (const edge &a)const{
        return w<a.w;
    }
}a[MAXN<<1],b[MAXN<<1];
 
void push(int u,int v,int w){
    a[e].u=u;
    a[e].v=v;
    a[e].w=w;
    a[e].next=first[u];
    first[u]=e++;
}
 
int fa[MAXN];
 
int find(int x){
    if(fa[x]!=x)    
        fa[x]=find(fa[x]);
    return fa[x];
}
 
void Bfs(){
    bool vis[MAXN];
    memset(vis,0,sizeof vis);
    queue<int>q;
    q.push(1);
    vis[1]=1;
    while(!q.empty()){
        int k = q.front();
        q.pop();
        for(int i=first[k];i;i=a[i].next){
            if(!vis[a[i].v]){
                f[a[i].v]=k;
                cost[a[i].v]=a[i].w;
                vis[a[i].v]=1;
                q.push(a[i].v);
            }
        }
    }
}
 
void Kr(){
    sort(b+1,b+1+m);
    int cnt = 0;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int u = find(b[i].u),v=find(b[i].v);
        if(u==v)continue;
        fa[u]=v;
        push(b[i].u,b[i].v,b[i].w);
        push(b[i].v,b[i].u,b[i].w);
        if(cnt==n-1)break;
    }
    Bfs();
}
 
struct Tree{
    Tree *ls,*rs;
    multiset<int>*v;
    int min_x;
     
    Tree()  { ls=rs=NULL,v=NULL,min_x=inf; }
     
    void Push_up(){
        #define MIN(x) ((x)?((x)->min_x):inf)
        min_x=min(MIN(ls),MIN(rs));
    }
 
    void* operator new (size_t);
 
    void operator delete(void* p);
}*root[MAXN],*S,*T;
 
vector<Tree*>bin;
 
void* Tree :: operator new(size_t size){
    Tree *o;
    if(!bin.empty()){
        o=bin.back();
        bin.pop_back();
    }
    else{
        if(S==T){
            S=new Tree[1<<15];
            T=S+(1<<15);
        }
        o = S++;
    }
    o->ls=o->rs=NULL;
    o->v=NULL;
    o->min_x=inf;
    return o;
}
 
void Tree :: operator delete (void* p){
    bin.push_back((Tree*)p);
}
 
void insert(Tree *&o,int l,int r,int x,int va){
    if(!o)o = new Tree;
    if(l==r){
        if(!o->v)o->v=new multiset<int>;
        o->v->insert(va);
        o->min_x=*(o->v->begin());
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)insert(o->ls,l,mid,x,va);
    else insert(o->rs,mid+1,r,x,va);
    o->Push_up();
}
 
void erase(Tree *&o,int l,int r,int x,int va){
    if(l==r){
        o->v->erase(o->v->find(va));
        if(o->v->empty()){
            delete o->v;
            o->v=NULL;
            delete o;
            o=NULL;
        }
        else o->min_x=*(o->v->begin());
        return;
    }
    int mid = l+r>> 1;
    if(x<=mid)erase(o->ls,l,mid,x,va);
    else erase(o->rs,mid+1,r,x,va);
    o->Push_up();
    if(o->min_x==inf){
        delete o;
        o=NULL;
    }
}
 
int query(Tree *o,int l,int r,int x,int y){
    if(!o)return inf;
    if(x<=l&&r<=y)return o->min_x;
    int mid = l+r>>1,ans=inf;
    if(x<=mid)ans=min(ans,query(o->ls,l,mid,x,y));
    if(mid<y)ans=min(ans,query(o->rs,mid+1,r,x,y));
    return ans;
}
 
int Query(int x){
    int ans = inf;
    if(val[x]!=1)ans=min(ans,query(root[x],1,k,1,val[x]-1));
    if(val[x]!=k)ans=min(ans,query(root[x],1,k,val[x]+1,k));
    return ans;
}
 
int main(){
    //freopen("grass.in","r",stdin);
    //freopen("grass.out","w",stdout);
    bin.clear();
    n=read<int>();
    m=read<int>();
    k=read<int>();
    q=read<int>();
    for(int i=1;i<=m;i++)scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w);
    for(int i=1;i<=n;i++)scanf("%d",&val[i]);Kr();
    for(int i=2;i<=n;i++)insert(root[f[i]],1,k,val[i],cost[i]);
    for(int i=1;i<=n;i++)Ans.insert(last[i]=Query(i));
    while(q--){
        int pos=read<int>(),w=read<int>();
         
        if(f[pos])erase(root[f[pos]],1,k,val[pos],cost[pos]);
         
        val[pos]=w;
 
        if(f[pos])insert(root[f[pos]],1,k,val[pos],cost[pos]);
 
        Ans.erase(Ans.find(last[pos]));
        Ans.insert(last[pos]=Query(pos));
 
        if(f[pos]){
            Ans.erase(Ans.find(last[f[pos]]));
            Ans.insert(last[f[pos]]=Query(f[pos]));
        }
 
        printf("%d\n",*(Ans.begin()));
    }
}




Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值