UVA 11457


Problem B: Classified

Classification levels like Secret and Top Secret are well-known features of military documents. Less well known are integrity levels, which correspond to how reliable information is.

In the Dynamic Biba integrity model, every user and every document is assigned an integrity level. If a user writes to a document that has a higher integrity level than the user does, the document’s integrity level goes down. Similarly, if a user reads a document that has a lower integrity level than the user does, the user’s integrity level goes down.

Your job is to keep track of the integrity levels of a number of users and documents. Complicating the matter is the fact that integrity levels aren’t simply numbers; a document might contain very trusworthy information about operations in Afganistan, while at the same time containing less trustworthy information about operations in Iraq.

Integrity levels are speficied by arbitrary labels, along with rules of the form A → B, indicating that integrity level A is at most as trustworthy as integrity level B. The rules satisfy a number of conditions:

  • For any label AA → A is always true, and need not be specified.
  • If A and B are two different labels, then it can never be the case that both A → B and B → A are true. However, it can be the case that neither A → B nor B → A are true.
  • For any labels AB, and C, if it is the case that A → B and B → C are both true, you can conclude (without it being explicitly specified) that A → C is true.
  • For any two labels A and B, there is a label G = glb(A,B) called the greatest lower bound of A and Bsuch that G → A and G → B are both true. Further, for any label L such that L → A and L → B are both true, it is also the case that L → G is true.

You will be given as input the labels and rules defining the integrity levels, as well as the initial integrity level of a number of users and a number of documents.

The first line is the number of test cases to follow. The test cases follow, one after another; the format of each test case is the following:

The format will be as follows:

  • The first line of the input will contain five integers separated by spaces. These integers are the number of integrity levels ℓ, the number of rules r, the number of users u, the number of documents d, and the number of actions a, in that order. None of these five integers will be greater than 10000. The integrity levels are numbered from 1 to ℓ; the users from 1 to u, and the documents from 1 to d.
  • The next r lines specify the rules. Each line will consist of two integers between 1 and ℓ, separated by a space. The line “x y” indicates that integrity level x is at most as trustworthy as integrity level y (i.e. x → y)
  • The next u lines specify the initial integrity levels for user number 1, 2, …, u. Each line will be an integrity level number, from 1 to ℓ.
  • The next d lines specify the initial integrity levels for document number 1, 2, …, d. Each line will be an integrity level number, from 1 to ℓ.
  • The next a lines specify the actions; each action will be of one of the following two forms (here, useris an integer between 1 and u, and document is an integer between 1 and d):
    • user reads document: The given user is reading the given document. The integrity level for the user should be changed to the glb of the old integrity level for the user and the integrity level of the document. Output the new integrity level for the user on a line by itself.
    • user writes document: The given user is writing to the given document. The integrity level for the document should be changed to the glb of the integrity level for the user and the old integrity level of the document. Output the new integrity level for the document on a line by itself.

Sample input:

1
9 11 2 3 5
6 9
2 6
9 4
7 5
3 8
7 2
5 3
8 4
5 1
6 1
1 8
4
2
5
9
8
1 reads 3
1 writes 2
2 reads 2
1 reads 1
2 writes 1

Output for sample input:

8
6
2
5
7

Ian Goldberg



本题就是在一个DGA上求解两点的最近公共祖先,这可以用点与点之间的距离取求解。现在假设有两点i,j,我们要求解lca(i,j).

假设 lca(i,j)=k,且p也是i,j的一个祖先,那么有:

d[p][i]+d[p][j]=2*d[p][k]+d[k][i]+d[k][j]>d[k][i]+d[k][j].(d[i][j]表示i,j间的距离)

所以对于每一个询问(i,j),我们只需要求找到一个k使得d[k][i]+d[k][j]取到最小值,本题先预处理出所有距离的话会超时,所以我们需要建反图,对每个询问求一次i,j的单源最短路即可,考虑到图是DGA,dfs就可以实现单源最短路。  


代码:

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define maxn 10009
#define INF 100000000
using namespace std;
int dis[maxn][maxn];
int lca[maxn][maxn];
int user[maxn],doc[maxn];
bool vis[maxn];
int first[maxn];
int v[maxn],next[maxn];int tot;
void add(int x,int y)
{
    v[tot]=y;
    next[tot]=first[x];
    first[x]=tot++;
}
void dfs(int cur,int dep,int *d)
{
    d[cur]=min(d[cur],dep);
    for(int e=first[cur];e!=-1;e=next[e])
        dfs(v[e],dep+1,d);
}
int n,m,u,d,a;
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d%d%d%d",&n,&m,&u,&d,&a);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            if(i==j)dis[i][j]=0;
            else dis[i][j]=INF;
        memset(first,-1,sizeof(first));tot=0;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(y,x);
        }
        for(int i=1;i<=u;i++)
            scanf("%d",&user[i]);
        for(int i=1;i<=d;i++)
        {
            scanf("%d",&doc[i]);
        }
        memset(vis,0,sizeof(vis));
        for(int i=0;i<a;i++)
        {
            int x,y;
            char s[10];
            scanf("%d%s%d",&x,s,&y);
            if(s[0]=='r')
            {
                if(!vis[user[x]]){
                dfs(user[x],0,dis[user[x]]);
                vis[user[x]]=1;}
                if(!vis[doc[y]]){
                    dfs(doc[y],0,dis[doc[y]]);
                    vis[doc[y]]=1;
                }
                int pp=user[x],qq=doc[y];
			  int cur=INF;
                    for(int i=1;i<=n;i++)
                    {

                        if(cur>dis[pp][i]+dis[qq][i])
                        {
                            cur=dis[pp][i]+dis[qq][i];
                            user[x]=i;
                        }
                    }
                printf("%d\n",user[x]);
            }
            else
            {
                if(!vis[user[x]]){
                dfs(user[x],0,dis[user[x]]);
                vis[user[x]]=1;}
                if(!vis[doc[y]]){
                    dfs(doc[y],0,dis[doc[y]]);
                    vis[doc[y]]=1;
                }
                int pp=user[x],qq=doc[y];
                 int cur=INF;
                    for(int i=1;i<=n;i++)
                    {

                        if(cur>dis[pp][i]+dis[qq][i])
                        {
                            cur=dis[pp][i]+dis[qq][i];
                            doc[y]=i;
                        }
                    }
                printf("%d\n",doc[y]);
            }
        }

    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值