百度科学家(简单)(中等)(困难)


困难版

题意有些绕 这就不说了 一个点对一个连续区间内的所有点连一条权值相同的边 这个线性的过程可以用线段树来优化
但是这道题中每个位置上的元素会改变 这样只用线段树是无法维护的 需要用主席树来维护 这也没啥好说的 学了主席树其中道理自然明白 然后就是tarjan缩点后贪心 找出度为零的强连通分量加和的最小值
直接上代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f

struct node1
{
    int nl;
    int nr;
};

struct node2
{
    int v;
    int next;
};

stack <int> stk;
node1 tree[2000010];
node2 edge[8000010];
ll val[100010],sum[2000010];
int root[100010],f[100010],mp[100010],fmp[2000010];
int first[2000010],dfn[2000010],low[2000010],book[2000010],belong[2000010],degree[2000010];
int n,q,gou,now,gg,tot,num,cnt;

void addedge(int u,int v)
{
    edge[num].v=v;
    edge[num].next=first[u];
    first[u]=num++;
    return;
}

int build(int l,int r)
{
    int cur,m;
    cur=gou++;
    tree[cur].nl=0,tree[cur].nr=0;
    if(l==r)
    {
        mp[l]=cur;
        fmp[cur]=l;
        return cur;
    }
    m=(l+r)/2;
    tree[cur].nl=build(l,m);
    tree[cur].nr=build(m+1,r);
    addedge(cur,tree[cur].nl);
    addedge(cur,tree[cur].nr);
    return cur;
}

int update(int rot,int tar,int l,int r)
{
    int cur,m;
    cur=gou++;
    tree[cur]=tree[rot];
    if(l==r)
    {
        mp[f[tar]]=cur;//
        fmp[cur]=f[tar];
        return cur;
    }
    m=(l+r)/2;
    if(tar<=m) tree[cur].nl=update(tree[rot].nl,tar,l,m);
    else tree[cur].nr=update(tree[rot].nr,tar,m+1,r);
    addedge(cur,tree[cur].nl);
    addedge(cur,tree[cur].nr);
    return cur;
}

void solve(int rot,int tar,int pl,int pr,int l,int r)
{
    int m;
    if(pl<=l&&r<=pr)
    {
        addedge(tar,rot);
        return;
    }
    m=(l+r)/2;
    if(pl<=m) solve(tree[rot].nl,tar,pl,pr,l,m);
    if(pr>m) solve(tree[rot].nr,tar,pl,pr,m+1,r);
    return;
}

void dfs(int u)
{
    int i,v;
    stk.push(u);
    book[u]=1;
    num++;
    dfn[u]=num;
    low[u]=num;
    for(i=first[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(dfn[v]==0)
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(book[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        cnt++;
        while(!stk.empty())
        {
            v=stk.top();
            stk.pop();
            book[v]=0;
            belong[v]=cnt;
            if(fmp[v]!=-1) sum[belong[v]]+=val[fmp[v]];
            if(u==v) break;
        }
    }
    return;
}

void tarjan()
{
    ll minn;
    int i,u,v;
    while(!stk.empty()) stk.pop();
    tot=mp[gg],num=0,cnt=0;
    for(i=0;i<=tot;i++)
    {
        dfn[i]=0;
        low[i]=0;
        book[i]=0;
        belong[i]=0;
        sum[i]=0;
        degree[i]=0;
    }

    /*
    for(i=1;i<=tot;i++)
    {
        printf("***%d***\n",i);
        for(int j=first[i];j!=-1;j=edge[j].next)
        {
            printf("%d ",edge[j].v);
        }
        printf("\n");
    }
    */

    for(i=1;i<=tot;i++)
    {
        if(dfn[i]==0)
        {
            dfs(i);
        }
    }
    /*
    printf("%d\n",cnt);
    for(i=1;i<=tot;i++)
    {
        printf("%d ",belong[i]);
    }
    printf("\n");
    */
    for(u=1;u<=tot;u++)
    {
        for(i=first[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            if(belong[u]!=belong[v])
            {
                degree[belong[u]]++;
            }
        }
    }
    minn=N;
    for(i=1;i<=cnt;i++)
    {
        if(degree[i]==0)
        {
            minn=min(minn,sum[i]);
        }
    }
    printf("%lld\n",minn);
    return;
}

int main()
{
    ll y;
    int i,op,x,l,r;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&val[i]);
    }
    memset(root,0,sizeof(root));
    memset(first,-1,sizeof(first));
    memset(fmp,-1,sizeof(fmp));
    for(i=1;i<=n;i++) f[i]=i;
    gou=1,now=0,gg=n,num=0;
    root[0]=build(1,n);
    scanf("%d",&q);
    for(i=1;i<=q;i++)
    {
        scanf("%d",&op);
        if(op==0)
        {
            scanf("%d%lld",&x,&y);
            gg++;
            val[gg]=y;
            f[x]=gg;
            now++;
            root[now]=update(root[now-1],x,1,n);
        }
        else
        {
            scanf("%d%d%d",&x,&l,&r);
            solve(root[now],mp[f[x]],l,r,1,n);
        }
    }
    tarjan();
    return 0;
}

中等版
数据量放小了很多 直接缩点即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f

struct node
{
    int v;
    int next;
};

stack <int> stk;
node edge1[400010],edge2[400010];
ll pre[200010],sum[200010];
int first1[200010],first2[200010];
int f[200010],dfn[200010],low[200010],book[200010],belong[200010],degree[200010];
int n,num,cnt;

void addedge(node* edge,int* first,int u,int v)
{
    edge[num].v=v;
    edge[num].next=first[u];
    first[u]=num++;
    return;
}

void dfs(int cur)
{
    int i,v;
    stk.push(cur);
    dfn[cur]=num,low[cur]=num,book[cur]=1;
    num++;
    for(i=first1[cur];i!=-1;i=edge1[i].next)
    {
        v=edge1[i].v;
        if(!dfn[v])
        {
            dfs(v);
            low[cur]=min(low[cur],low[v]);
        }
        else if(book[v])
        {
            low[cur]=min(low[cur],dfn[v]);
        }
    }
    if(dfn[cur]==low[cur])
    {
        cnt++;
        while(!stk.empty())
        {
            v=stk.top();
            stk.pop();
            book[v]=0;
            belong[v]=cnt;
            sum[cnt]+=pre[v];
            if(cur==v) break;
        }
    }
    return;
}

void tarjan()
{
    int i,u,v;
    while(!stk.empty()) stk.pop();
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(book,0,sizeof(book));
    memset(belong,0,sizeof(belong));
    memset(sum,0,sizeof(sum));
    num=1,cnt=0;
    for(u=1;u<=n;u++)
    {
        if(!dfn[u]) dfs(u);
    }
    memset(degree,0,sizeof(degree));
    for(u=1;u<=n;u++)
    {
        for(i=first1[u];i!=-1;i=edge1[i].next)
        {
            v=edge1[i].v;
            if(belong[u]!=belong[v])
            {
                degree[belong[u]]++;
            }
        }
    }
    return;
}

int main()
{
    ll val,ans;
    int i,q,op,tar,l,r;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&pre[i]);
    }
    memset(first1,-1,sizeof(first1));
    for(i=1;i<=n;i++) f[i]=i;
    num=0;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&op);
        if(op==0)
        {
            scanf("%d%lld",&tar,&val);
            n++;
            f[tar]=n;
            pre[n]=val;
        }
        else
        {
            scanf("%d%d%d",&tar,&l,&r);
            for(i=l;i<=r;i++)
            {
                if(i!=tar)
                {
                    addedge(edge1,first1,f[tar],f[i]);
                }
            }
        }
    }
    tarjan();
    ans=N;
    for(i=1;i<=cnt;i++)
    {
        if(degree[i]==0)
        {
            ans=min(ans,sum[i]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}


简单版
队友写的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e5+5000;
int n,m;
vector<int> g[maxn];
int val[maxn], id[maxn],vis[maxn];
ll tmp_ans;
void dfs(int u) {
	tmp_ans += val[u];
	vis[u] = 1;
	for(int i = 0; i < g[u].size(); ++i) {
		int v = g[u][i];
		if(vis[v]) continue;
		dfs(v);
	}
}
ll work(int x) {
	memset(vis, 0, sizeof vis);
	tmp_ans = 0;
	dfs(x);
	return tmp_ans;
}
int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
    {
		scanf("%d", &val[i]);
		id[i] = i;
	}
	scanf("%d", &m);
	int cnt = n;
	for(int ii = 1; ii <= m; ++ii) {
		int key; scanf("%d", &key);
		if(key == 0) {
			int x, y;
			scanf("%d %d", &x, &y);
			id[x] = ++cnt;
			val[cnt] = y;
		}
		else {
			int x, l, r;
			scanf("%d %d %d", &x, &l, &r);
			for(int i = l; i <= r; ++i) {
				g[id[x]].push_back(id[i]);
			}
		}
	}
	ll ans = inf;
	for(int i = 1; i <= cnt; ++i) {
		ans = min(work(i), ans);
	}
	printf("%lld\n", ans);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/80295034
今日推荐