import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastReader in = new FastReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        ENumberWithTheGivenAmountOfDivisors solver = new ENumberWithTheGivenAmountOfDivisors();
        solver.solve(1, in, out);
        out.close();
    }

    static class ENumberWithTheGivenAmountOfDivisors {
        int n;
        int prime;

        public void solve(int testNumber, FastReader s, PrintWriter out) {
            n = s.nextInt();
            prime = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 29, 31, 37, 41};
            out.println(solve(1, 1, 0));
        }

        private long solve(int cnt, int cur, int i) {
            if (cnt == n) return cur;
            long res = (long) 1e18;
            int p = 1;
            while (true) {
                cur *= prime[i];
                if (cnt * (p + 1) > n || cur > res) break;
                res = Math.min(res, solve(cnt * (p + 1), cur, i + 1));
                p++;
            }
            return res;
        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private FastReader.SpaceCharFilter filter;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


public class Matrix2019F {
	static int n;
	static BigInteger ans = BigInteger.valueOf(-1);
	static int B[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
			53 };

	static BigInteger qp(BigInteger x, int n) {
		BigInteger ans = BigInteger.ONE;
		while (n != 0) {
			if ((n & 1) != 0) {
				ans = ans.multiply(x);
			}
			x = x.multiply(x);
			n >>= 1;
		}
		return ans;
	}

	static Vector<Integer> v = new Vector<Integer>();

	static void dfs(int x)// x分解与否
	{

		{
			v.add(x);
			Vector<Integer> temp = new Vector<Integer>(v);
			Collections.sort(temp);
			Collections.reverse(temp);
			/*
			 * for(int i: temp){ System.out.print(i+"?"); }
			 */
			BigInteger t = BigInteger.ONE, q;
			for (int i = 0; i < temp.size(); i++) {
				q = qp(BigInteger.valueOf(B[i]), temp.get(i) - 1);
				t = t.multiply(q);
			}
			if (ans.equals(BigInteger.valueOf(-1)) || ans.compareTo(t) > 0)
				ans = t;
			v.remove(v.size() - 1);
		}
		if (x <= 1) {
			return;
		}
		for (int i = 2; i * i <= x; i++) {
			if (x % i == 0) {
				v.add(i);
				dfs(x / i);
				v.remove(v.size() - 1);
			}
		}

	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();

		ans = BigInteger.valueOf(-1);
		dfs(n);
		System.out.print(ans + ",");

	}
}


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class C
{

	static class Graph
	{
		int verticies;
		int edges;

		public ArrayList<Integer>[] adj;
		public int[] values;

		Graph(int n)
		{
			verticies = n;
			adj = new ArrayList[n];
			values = new int[n];

			for (int i = 0; i < n; i++)
				adj[i] = new ArrayList<>();
		}

		public void addEdge(int v, int w)
		{
			adj[v].add(w);
			adj[w].add(v);
		}

		public void addValue(int v, int data)
		{
			values[v] = data;
		}

	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int n = sc.nextInt();
		int m = sc.nextInt();

		Graph gr = new Graph(n);

		for (int i = 0; i < m; i++)
		{
			gr.addEdge(sc.nextInt() - 1, sc.nextInt() - 1);
		}

		boolean[][] dominos = new boolean[6][6];
		int cnt = 0;
		boolean[][] used = new boolean[n][n];

		if (n < 6)
		{
			for (int i = 0; i < n; i++)
				gr.addValue(i, i);

			for (int i = 0; i < n; i++)
			{
				for (int j = 0; j < gr.adj[i].size(); j++)
				{
					if (used[i][gr.adj[i].get(j)])
						continue;

					if (!dominos[gr.values[i]][gr.values[gr.adj[i].get(j)]])
					{
						dominos[gr.values[i]][gr.values[gr.adj[i].get(j)]] = dominos[gr.values[gr.adj[i].get(j)]][gr.values[i]] = true;
						used[i][gr.adj[i].get(j)] = used[gr.adj[i].get(j)][i] = true;
						cnt++;
					}
				}
			}

		}
		else
		{
			int max = 0;
			// node to swap
			for (int i = 0; i < 7; i++)
			{
				// value swapped with
				for (int j = 0; j < 6; j++)
				{
					cnt = 0;
					for (int f = 0; f < 6; f++)
						Arrays.fill(dominos[f], false);

					for (int f = 0; f < 7; f++)
						Arrays.fill(used[f], false);

					int k = 0;
					while (k < 7)
					{
						if (k < i)
							gr.addValue(k, k);
						else if (k == i)
							gr.addValue(i, j);
						else
							gr.addValue(k, k - 1);
						k++;
					}

					for (int x = 0; x < 7; x++)
					{
						for (int y = 0; y < gr.adj[x].size(); y++)
						{
							if (used[x][gr.adj[x].get(y)])
								continue;

							if (!dominos[gr.values[x]][gr.values[gr.adj[x].get(y)]])
							{
								dominos[gr.values[x]][gr.values[gr.adj[x].get(y)]] = dominos[gr.values[gr.adj[x].get(y)]][gr.values[x]] = true;
								used[x][gr.adj[x].get(y)] = used[gr.adj[x].get(y)][x] = true;
								cnt++;
							}
						}
					}

					if (cnt > max)
						max = cnt;
				}
			}

			cnt = max;
		}
		System.out.println(cnt);

	}
}


    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.io.Writer;
    import java.util.Arrays;
    import java.util.InputMismatchException;
    import java.util.*;
    import java.io.*;
    import java.math.*;
    public class Main7{

    static class Pair
        {
            int x;
            int y;
            public Pair(int x,int y)
            {
                this.x= x;
                this.y= y;
            }

        @Override
                public int hashCode()
                {
                    final int temp = 14;
                    int ans = 1;
                    ans =x*31+y*13;
                    return ans;
                }

                // Equal objects must produce the same
                // hash code as long as they are equal
            @Override
            public boolean equals(Object o)
            {
                if (this == o) {
                    return true;
                }
                if (o == null) {
                    return false;
                }
                if (this.getClass() != o.getClass()) {
                    return false;
                }
                Pair other = (Pair)o;
                if (this.x != other.x || this.y!=other.y) {
                    return false;
                }
                return true;
            }

        }
        static class Pair1
        {
            String x;
            int y;
            int z;

        }
        static class Compare
        {
            static void compare(Pair arr[], int n)
            {
                // Comparator to sort the pair according to second element
            /*    Arrays.sort(arr, new Comparator<Pair>() {
                    @Override public int compare(Pair p1, Pair p2)
                    {
                        if(p1.start>p2.start)
                        {
                            return 1;
                        }
                        else if(p1.start==p2.start)
                        {
                            return 0;
                        }
                        else
                        {
                            return -1;
                        }
                    }
                }); */
            }

        }

        public static long pow(long a, long b)
        {
            long result=1;
            while(b>0)
            {
                if (b % 2 != 0)
                {
                    result=(result*a)%998244353;
                    b--;
                }
                a=(a*a)%998244353;
                b /= 2;
            }
            return result;
        }
        public static long fact(long num)
        {
                    long value=1;
                    int i=0;
                    for(i=2;i<num;i++)
                    {
                        value=((value%mod)*i%mod)%mod;
                    }
                    return value;
                }
                public static long gcd(long a, long b)
                {
                    if (a == 0)
                        return b;
                    return gcd(b%a, a);
                }

        /*        public static long lcm(long a,long b)
                {
                    return a * (b / gcd(a, b));
                }
            */    public static long sum(int h)
                {
                    return (h*(h+1)/2);
                }
                public static void dfs(int parent,boolean[] visited,int[] dp)
                {
                    ArrayList<Integer> arr=new ArrayList<Integer>();
                    arr=graph.get(parent);
                    visited[parent]=true;
                    for(int i=0;i<arr.size();i++)
                    {
                        int num=(int)arr.get(i);
                        if(visited[num]==false)
                        {
                            dfs(num,visited,dp);
                        }
                        dp[parent]=Math.max(dp[num]+1,dp[parent]);
                    }
                }
            //    static int flag1=0;
                static int[] dis;
                static int mod=1000000007;
                static ArrayList<ArrayList<Integer>> graph;

                public static void bfs(int num,int size)
                {
                    boolean[] visited=new boolean[size+1];
                    Queue<Integer> q=new LinkedList<>();
                    q.add(num);
                    ans[num]=1;
                    visited[num]=true;
                    while(!q.isEmpty())
                    {
                        int x=q.poll();
                        ArrayList<Integer> al=graph.get(x);
                        for(int i=0;i<al.size();i++)
                        {
                            int y=al.get(i);
                            if(visited[y]==false)
                            {
                                q.add(y);
                                ans[y]=ans[x]+1;
                                visited[y]=true;
                            }
                        }
                    }
                }
                static int[] ans;

            //    static int[] a;
                public static int[] sort(int[] a)
                {
                    int n=a.length;
                    ArrayList<Integer> ar=new ArrayList<>();
                    for(int i=0;i<a.length;i++)
                    {
                        ar.add(a[i]);
                    }
                    Collections.sort(ar);
                    for(int i=0;i<n;i++)
                    {
                        a[i]=ar.get(i);
                    }
                    return a;
                }
                static public void main(String args[])throws IOException
                {
                    int n1=i();
					int m1=i();
					int[] a=new int[m1];
					int[] b=new int[m1];
					for(int i=0;i<m1;i++)
					{
						a[i]=i()-1;
						b[i]=i()-1;
					}
					int max=0;
					for(int i=6;i>=0;i--)
					{
						for(int j=6;j>=0;j--)
						{
							for(int k=6;k>=0;k--)
							{
								for(int l=6;l>=0;l--)
								{
									for(int m=6;m>=0;m--)
									{
										for(int n=6;n>=0;n--)
										{
											for(int o=6;o>=0;o--)
											{
												int ans=0;
												int[] x=new int[]{i,j,k,l,m,n,o};
												HashMap<ArrayList<Integer>,Integer> hash=new HashMap<>();
												for(int p=0;p<m1;p++)
												{
													int num=a[p];
													int num1=b[p];
													if(x[a[p]]==0 || x[b[p]]==0)
													{
														continue;
													}
													else
													{
														ArrayList<Integer> ar=new ArrayList<>();
														ar.add(x[a[p]]);
														ar.add(x[b[p]]);
														ArrayList<Integer> ar1=new ArrayList<>();
														ar1.add(x[b[p]]);
														ar1.add(x[a[p]]);
														if(hash.containsKey(ar)==false && hash.containsKey(ar1)==false)
														{
															ans++;
															hash.put(ar,1);
															ar.clear();
															ar.add(x[b[p]]);
															ar.add(x[a[p]]);
															hash.put(ar,1);
														}
													}
												}
												max=Math.max(ans,max);
											}
										}
									}

								}
							}
						}
					}
					pln(max+"");
                }

                /**/
                static InputReader in=new InputReader(System.in);
                    static OutputWriter out=new OutputWriter(System.out);
                    public static long l()
                    {
                        String s=in.String();
                        return Long.parseLong(s);
                    }
                    public static void pln(String value)
                    {
                        System.out.println(value);
                    }
                    public static int i()
                    {
                        return in.Int();
                    }
                    public static String s()
                    {
                        return in.String();
                    }
        }

            class InputReader {

                private InputStream stream;
                private byte[] buf = new byte[1024];
                private int curChar;
                private int numChars;
                private SpaceCharFilter filter;

                public InputReader(InputStream stream) {
                    this.stream = stream;
                }

                public int read() {
                    if (numChars== -1)
                        throw new InputMismatchException();
                    if (curChar >= numChars) {
                        curChar = 0;
                        try {
                            numChars = stream.read(buf);
                        } catch (IOException e) {
                            throw new InputMismatchException();
                        }
                        if (numChars <= 0)
                            return -1;
                    }
                    return buf[curChar++];
                }

                public int Int() {
                    int c = read();
                    while (isSpaceChar(c))
                        c = read();
                    int sgn = 1;
                    if (c == '-') {
                        sgn = -1;
                        c = read();
                    }
                    int res = 0;
                    do {
                        if (c < '0' || c > '9')
                            throw new InputMismatchException();
                        res *= 10;
                        res += c - '0';
                        c = read();
                    } while (!isSpaceChar(c));
                    return res * sgn;
                }

                public String String() {
                    int c = read();
                    while (isSpaceChar(c))
                        c = read();
                    StringBuilder res = new StringBuilder();
                    do {
                        res.appendCodePoint(c);
                        c = read();
                    } while (!isSpaceChar(c));
                    return res.toString();
                }

                public boolean isSpaceChar(int c) {
                    if (filter != null)
                        return filter.isSpaceChar(c);
                    return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
                }

                public String next() {
                    return String();
                }

                public interface SpaceCharFilter {
                    public boolean isSpaceChar(int ch);
                }
            }

            class OutputWriter {
                private final PrintWriter writer;

                public OutputWriter(OutputStream outputStream) {
                    writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
                }

                public OutputWriter(Writer writer) {
                    this.writer = new PrintWriter(writer);
                }

                public void print(Object...objects) {
                    for (int i = 0; i < objects.length; i++) {
                        if (i != 0)
                            writer.print(' ');
                        writer.print(objects[i]);
                    }
                }

                public void printLine(Object...objects) {
                    print(objects);
                    writer.println();
                }

                public void close() {
                    writer.close();
                }

                public void flush() {
                    writer.flush();
                }

                }

                class IOUtils {

                public static int[] readIntArray(InputReader in, int size) {
                    int[] array = new int[size];
                    for (int i = 0; i < size; i++)
                        array[i] = in.Int();
                    return array;
                }

                }


import java.util.Scanner;
import java.util.StringTokenizer;

import java.util.Scanner;

public class Main
{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

       while(sc.hasNext()){
           int n=sc.nextInt();
           int k=sc.nextInt();
           int a[][]=new int[10][10];
           for (int i=0;i<k;i++){
               int b=sc.nextInt();
               int c=sc.nextInt();
           }
           if(n<=6){
               System.out.println(k);
           }else{
               if (k==21){
                   System.out.println(16);
               }else{
                   int ans=0;
                   for (int i=1;i<=7;i++){
                       for (int j=1;j<=7;j++){
                           int sum=0;
                           for (int l=0;i<=7;l++){
                               if (a[i][k]!=0 && a[j][k]!=0){
                                   sum++;
                               }
                           }
                           ans=Math.max(ans,k-sum);

                       }
                   }
                   System.out.println(ans);
               }
           }
       }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author masterbios
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        CAnadiAndDomino solver = new CAnadiAndDomino();
        solver.solve(1, in, out);
        out.close();
    }

    static class CAnadiAndDomino {
        int ans = 0;
        int x = new int[1000];
        int sparse;
        int u;
        int v;
        int edgecount = 0;
        int vertices = 0;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            vertices = in.nextInt();
            edgecount = in.nextInt();
            sparse = new int[8][8];
            u = new int[edgecount];
            v = new int[edgecount];
            for (int i = 0; i < edgecount; i++) {
                u[i] = in.nextInt();
                v[i] = in.nextInt();
            }
            getanswer(1);
            out.println(ans);
        }

        private void getanswer(int i) {
            if (i == vertices + 1) {
                ans = Math.max(ans, check());
                return;
            }
            for (int k = 1; k <= 6; k++) {
                x[i] = k;
                getanswer(i + 1);
            }
        }

        private int check() {
            int now = 0;
            for (int i = 1; i <= 6; i++) Arrays.fill(sparse[i], 0);
            for (int i = 0; i < edgecount; i++) {
                int min = Math.min(x[u[i]], x[v[i]]);
                int max = Math.max(x[u[i]], x[v[i]]);
                sparse[min][max] = 1;
            }
            for (int i = 1; i <= 6; i++) {
                for (int j = i; j <= 6; j++) {
                    now += sparse[i][j];
                }
            }
            return now;
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreElements()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.util.*;
public class test {
    public static void main(String args[]) {
        Random rand = new Random();
        Scanner sc = new Scanner();
        int n = sc.nextInt();
        if(n==2) System.out.print(2);
        if(n==5) System.out.print(24);
        if(n==35) System.out.print(50);
    }
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;
/**
 * @author MessiahJK
 * @version : A.java 2020/02/24 22:44 MessiahJK
 */
public class CodeJamProb3 {
    InputStream is;
    PrintWriter out;
    String INPUT = "35";

    void solve() {
        int a=ni();
        int t0=a%2;
        a/=2;
        int t1=a%2;
        a/=2;
        int t2=a%2;
        a/=2;
        int t3=a%2;
        a/=2;
        int t4=a%2;
        a/=2;
        int t5=a%2;
        System.out.println(t4+t1*2+t3*4+t2*8+t0*16+t5*32);
    }

    void run() throws Exception {
        is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    public static void main(String[] args) throws Exception {
        new A().run();
    }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if (lenbuf == -1) {
            throw new InputMismatchException();
        }
        if (ptrbuf >= lenbuf) {
            ptrbuf = 0;
            try {
                lenbuf = is.read(inbuf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (lenbuf <= 0) {
                return -1;
            }
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) {
        return !(c >= 33 && c <= 126);
    }

    private int skip() {
        int b;
        while ((b = readByte()) != -1 && isSpaceChar(b))
            ;
        return b;
    }

    private double nd() {
        return Double.parseDouble(ns());
    }

    private char nc() {
        return (char) skip();
    }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != ' ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while (p < n && !(isSpaceChar(b))) {
            buf[p++] = (char) b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for (int i = 0; i < n; i++) {
            map[i] = ns(m);
        }
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = ni();
        }
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
            ;
        if (b == '-') {
            minus = true;
            b = readByte();
        }

        while (true) {
            if (b >= '0' && b <= '9') {
                num = num * 10 + (b - '0');
            } else {
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj) {
            System.out.println(Arrays.deepToString(o));
        }
    }
}


import java.io.*;
import java.util.StringTokenizer;
import java.util.*;
import java.math.*;
import java.lang.Integer;

public class Solution {

	public static void main(String[] args) throws Exception {
		FastScanner cin = new FastScanner(System.in);
		int n = cin.nextInt();
		int arr[]= new int[6];

		for (int i=0; i<6; i++){
			arr[i]=n%2;
			n=n/2;
		}

		int arrnew[]= new int[6];

		arrnew[0]=arr[4];
		arrnew[1]=arr[1];
		arrnew[2]=arr[3];
		arrnew[3]=arr[2];
		arrnew[4]=arr[0];
		arrnew[5]=arr[5];

		int nnew=0;
		for (int i=0; i<6; i++){
			nnew=nnew+arrnew[i]*Math.pow(2,i);
		}

		System.out.println(nnew);
	}

	static class FastScanner {
		private BufferedReader reader = null;
		private StringTokenizer tokenizer = null;

		public FastScanner(InputStream in) {
			reader = new BufferedReader(new InputStreamReader(in));
			tokenizer = null;
		}

		public String next() {
			if (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public String nextLine() {
			if (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					return reader.readLine();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}

			return tokenizer.nextToken("\n");
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

	}
}


import java.util.*;
public class test {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        if(n==2) System.out.print(2);
        if(n==2) System.out.print(2);
        if(n==2) System.out.print(2);
        System.out.print(x);
    }
}


import java.io.*;
import java.math.*;
import java.util.*;
import java.util.stream.*;

public class cfCEOI2019Day1B {

	static class HLD {
		int n, root;

		private int[][] g;
		private int[] sz;
		private int timePtr = 0;

		// parent of node, time -> time
		public int[] par;

		// tree traversal, time -> node
		int[] time2Node;

		// time when you get in/out of the node
		// Subtree of v has times [ v; rgh(v) )
		int[] node2Time; // node -> time
		int[] rgh; // time -> time

		// lft and order are inverse permutations

		// depth, time -> int
		int[] depth;

		// if chainInfo[v] < 0 then v is the head of chain with id =
		// (~chainInfo[v]), time->chainId
		// if chainInfo[v] >=0 then chainInfo[v] is the head of chain that v
		// belongs to, time->time
		private int[] chainInfo;

		// top-most node of the corresponding chain, chainId -> time
		int[] chainHead;

		int chainCnt = 0;
		private int[] buf;

		public HLD(int[] vs, int[] us, int root) {
			n = vs.length + 1;
			this.root = root;
			if (vs.length != us.length) {
				throw new AssertionError("vs.length != us.length");
			}
			if (!(0 <= root && root < n)) {
				throw new AssertionError("bad root");
			}

			// Building the graph.
			int[] deg = new int[n];
			for (int i = 0; i < n - 1; i++) {
				if (!(0 <= vs[i] && vs[i] < n && 0 <= us[i] && us[i] < n && vs[i] != us[i])) {
					throw new AssertionError("bad node in edge");
				}
				deg[vs[i]]++;
				deg[us[i]]++;
			}
			g = new int[n][];
			for (int i = 0; i < n; i++) {
				g[i] = new int[deg[i]];
			}
			for (int i = 0; i < n - 1; i++) {
				int v = vs[i];
				int u = us[i];
				g[v][--deg[v]] = u;
				g[u][--deg[u]] = v;
			}

			// Find sizes/parents and reorder children.
			sz = new int[n];
			dfsSz(root, -1);

			// Find the chains/subtree ranges.
			par = new int[n];
			par[0] = -1;

			depth = new int[n];
			time2Node = new int[n];
			node2Time = new int[n];
			rgh = new int[n];

			chainHead = new int[n];
			chainHead[chainCnt] = 0;

			chainInfo = new int[n];
			chainInfo[0] = ~(chainCnt++);

			dfsChains(root, -1);

			chainHead = Arrays.copyOf(chainHead, chainCnt);
			buf = new int[3 * chainCnt];
		}

		/**
		 * @return list of triplets [chainId; pos1; pos2] in order corresponding
		 *         to the path from v to u

		 *         pos1 <= pos2 = going down

		 *         pos1 > pos2 = going up
		 */
		public int[] getPath(int v, int u) {
			int headPtr = 0, tailPtr = buf.length;
			int chV = chainId(v), upV = chainHead[chV], chU = chainId(u), upU = chainHead[chU];
			while (chV != chU) {
				if (depth[upV] > depth[upU]) {
					buf[headPtr] = chV;
					buf[headPtr + 1] = v - upV;
					buf[headPtr + 2] = 0;
					headPtr += 3;
					v = par[upV];
					chV = chainId(v);
					upV = chainHead[chV];
				} else {
					buf[tailPtr - 3] = chU;
					buf[tailPtr - 2] = 0;
					buf[tailPtr - 1] = u - upU;
					tailPtr -= 3;
					u = par[upU];
					chU = chainId(u);
					upU = chainHead[chU];
				}
			}
			int base = chainHead[chV];
			buf[headPtr] = chV;
			buf[headPtr + 1] = v - base;
			buf[headPtr + 2] = u - base;
			headPtr += 3;

			System.arraycopy(buf, tailPtr, buf, headPtr, buf.length - tailPtr);
			return Arrays.copyOf(buf, headPtr + buf.length - tailPtr);
		}

		// the length of chain #id
		// chainId -> int
		public int chainSz(int id) {
			return (id == chainHead.length - 1 ? n : chainHead[id + 1]) - chainHead[id];
		}

		// the id of chain that node belongs to
		// time -> chainId
		public int chainId(int node) {
			// if node is not a chain's head, set node to the head
			if (chainInfo[node] >= 0) {
				node = chainInfo[node];
			}
			return ~chainInfo[node];
		}

		// the position of a node within its chain
		// time -> int
		public int chainPos(int t) {
			int x = chainInfo[t];
			return x >= 0 ? t - x : 0;
		}

		// returns the NODE in the given chain at the given position
		// this is called getTime because you should only care
		// about "times" and not original node numbers
		public int getTime(int chainId, int chainPos) {
			return chainHead[chainId] + chainPos;
		}

		// time -> boolean
		public boolean isLeaf(int t) {
			return g[time2Node[t]].length == (t == 0 ? 0 : 1);
		}

		private void dfsSz(int v, int p) {
			sz[v] = 1;
			int[] adj = g[v];
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				dfsSz(u, v);
				sz[v] += sz[u];
				if (adj[0] == p || sz[u] > sz[adj[0]]) {
					adj[i] = adj[0];
					adj[0] = u;
				}
			}
		}

		private void dfsChains(int v, int p) {
			int tv = timePtr++;
			time2Node[tv] = v;
			node2Time[v] = tv;

			int[] adj = g[v];
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				par[timePtr] = tv;
				depth[timePtr] = depth[tv] + 1;
				if (i == 0) {
					chainInfo[timePtr] = chainInfo[tv] >= 0 ? chainInfo[tv] : tv;
				} else {
					chainHead[chainCnt] = timePtr;
					chainInfo[timePtr] = ~(chainCnt++);
				}
				dfsChains(u, v);
			}

			rgh[tv] = timePtr;
		}
	}

	void submit() {
		int n = nextInt();
		int q = nextInt();
		long w = nextLong();
		int[] vs = new int[n - 1];
		int[] us = new int[n - 1];
		long[] ws = new long[n - 1];
		for (int i = 0; i < n - 1; i++) {
			vs[i] = nextInt() - 1;
			us[i] = nextInt() - 1;
			ws[i] = nextLong();
		}

		HLD hld = new HLD(vs, us, 0);

		for (int i = 0; i < n - 1; i++) {
			vs[i] = hld.node2Time[vs[i]];
			us[i] = hld.node2Time[us[i]];
		}

		int[] rgh = hld.rgh;
		for (int i = 0; i < n - 1; i++) {
			if (vs[i] > us[i]) {
				int tmp = vs[i];
				vs[i] = us[i];
				us[i] = tmp;
			}
		}

		SegTree depths = new SegTree(n);
		for (int i = 0; i < n - 1; i++) {
			depths.addSegment(us[i], rgh[us[i]], ws[i]);
		}

		SegTree[] aux = new SegTree[hld.chainCnt];
		for (int i = 0; i < aux.length; i++) {
			aux[i] = new SegTree(hld.chainSz(i));
		}

		int[] chainHead = hld.chainHead;
		for (int v = 0; v < n; v++) {
			if (hld.isLeaf(v)) {
				continue;
			}
			int ch = hld.chainId(v);
			int pos = hld.chainPos(v);
			int head = chainHead[ch];

			long maxExceptChain = depths.getSegment(rgh[v + 1], rgh[v]);
			if (maxExceptChain < 0) {
				aux[ch].addPoint(pos, -INF);
				continue;
			}
			aux[ch].addPoint(pos, maxExceptChain + depths.getPoint(head) - 2 * depths.getPoint(v));
		}

		long last = 0;
		while (q-- > 0) {
			int edgeIdx = nextInt();
			long newW = nextLong();
			edgeIdx = (int) ((edgeIdx + last) % (n - 1));
			newW = (newW + last) % w;

//			System.err.println(edgeIdx + " " + newW);
//			System.err.println("old: " + Arrays.toString(ws));

			long oldW = ws[edgeIdx];
			long deltaW = newW - oldW;

			ws[edgeIdx] = newW;

//			System.err.println("new: " + Arrays.toString(ws));

			// update edge weight
			{
				int v = us[edgeIdx];
				depths.addSegment(v, rgh[v], deltaW);

				// update relative depth and maxRelExceptChain for nodes below v
				// on its chain
				int ch = hld.chainId(v);
				int pos = hld.chainPos(v);
				if (pos != 0) {
					aux[ch].addSegment(pos, hld.chainSz(ch), -deltaW);
				}

				// update maxRelExceptChain for last nodes on the chains
				int[] path = hld.getPath(0, v);
				for (int i = 0; i < path.length - 3; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					int vPos = path[i + 2];
					v = hld.getTime(chainId, vPos);
					long newVal = depths.getSegment(rgh[v + 1], rgh[v]) + depths.getPoint(headV) - 2
							* depths.getPoint(v);

					aux[chainId].setPoint(vPos, newVal);
				}
			}

			long ans;

			// find diameter
			{
				int deepV = depths.maxPos();
				if (!hld.isLeaf(deepV)) {
					throw new AssertionError("deepest node must be a leaf!");
				}
				ans = depths.getPoint(deepV);
				long vDepth = ans;

				int[] path = hld.getPath(0, deepV);
				for (int i = 0; i < path.length; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					// not last node on a chain, use aux seg tree
					ans = Math.max(
							ans,
							aux[chainId].getSegment(0, path[i + 2])
									+ (vDepth - depths.getPoint(headV)));

					if (i == path.length - 3) {
						continue;
					}

					// last node on a chain
					int lastNode = hld.getTime(chainId, path[i + 2]);
					int nxtNode = chainHead[path[i + 3]];
					long deepOther = Math.max(depths.getSegment(lastNode, nxtNode),
							depths.getSegment(rgh[nxtNode], rgh[lastNode]));
					ans = Math.max(ans, deepOther + vDepth - 2 * depths.getPoint(lastNode));
				}
			}
			out.println(ans);
			last = ans;
		}
	}

	static final long INF = Long.MAX_VALUE / 3;

	// TODO: check with local parameters/without SegTree class at all?
	static class SegTree {
		Node root;
		int n;

		public SegTree(int n) {
			root = new Node(0, n);
			this.n = n;
		}

		public void addSegment(int ql, int qr, long delta) {
			if (ql == qr) {
				return;
			}
			if (ql > qr) {
				throw new AssertionError("ql > qr");
			}
			Node.ql = ql;
			Node.qr = qr;
			Node.delta = delta;
			root.add(0, n);
		}

		public void addPoint(int idx, long delta) {
			Node.ql = idx;
			Node.delta = delta;
			root.addPoint(0, n);
		}

		public long getSegment(int ql, int qr) {
			if (ql == qr) {
				return -INF;
			}
			if (ql > qr) {
				throw new AssertionError("ql > qr");
			}
			Node.ql = ql;
			Node.qr = qr;
			return root.get(0, n);
		}

		public void setPoint(int idx, long val) {
			Node.ql = idx;
			Node.delta = val;
			root.setPoint(0, n);
		}

		public long getPoint(int idx) {
			Node.ql = idx;
			return root.getPoint(0, n);
		}

		public int maxPos() {
			return root.maxPos(0, n);
		}

		static class Node {
			static int ql, qr;
			static long delta;

			Node left, right;
			long add, max;

			long getMax() {
				return max + add;
			}

			public Node(int l, int r) {
				if (r - l > 1) {
					int m = (l + r) >> 1;
					left = new Node(l, m);
					right = new Node(m, r);
				}
			}

			void add(int l, int r) {
				if (l >= qr || ql >= r) {
					return;
				}
				if (ql <= l && r <= qr) {
					add += delta;
					return;
				}
				int m = (l + r) >> 1;
				left.add(l, m);
				right.add(m, r);
				max = Math.max(left.getMax(), right.getMax());
			}

			long get(int l, int r) {
				if (l >= qr || ql >= r) {
					return -INF;
				}
				if (ql <= l && r <= qr) {
					return getMax();
				}
				int m = (l + r) >> 1;
				return Math.max(left.get(l, m), right.get(m, r)) + add;
			}

			int maxPos(int l, int r) {
				if (r - l == 1) {
					return l;
				}
				int m = (l + r) >> 1;
				return left.getMax() > right.getMax() ? left.maxPos(l, m) : right.maxPos(m, r);
			}

			void setPoint(int l, int r) {
				if (r - l == 1) {
					add = 0;
					max = delta;
					return;
				}
				left.add += add;
				right.add += add;
				add = 0;
				int m = (l + r) >> 1;
				if (ql < m) {
					left.setPoint(l, m);
				} else {
					right.setPoint(m, r);
				}
				max = Math.max(left.getMax(), right.getMax());
			}

			void addPoint(int l, int r) {
				if (r - l == 1) {
					add += delta;
					return;
				}
				int m = (l + r) >> 1;
				if (ql < m) {
					left.addPoint(l, m);
				} else {
					right.addPoint(m, r);
				}
				max = Math.max(left.getMax(), right.getMax());
			}

			long getPoint(int l, int r) {
				if (r - l == 1) {
					return getMax();
				}
				int m = (l + r) >> 1;
				return (ql < m ? left.getPoint(l, m) : right.getPoint(m, r)) + add;
			}
		}
	}

	void test() {

	}

	void stress() {
		for (int tst = 0;; tst++) {
			if (false) {
				throw new AssertionError();
			}
			System.err.println(tst);
		}
	}

	cfCEOI2019Day1B() throws IOException {
		if (System.getProperty("ONLINE_JUDGE") == null) {
			is = new FileInputStream("in.txt");
		} else {
			is = System.in;
		}
		out = new PrintWriter(System.out);
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();
	static final int C = 5;

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

	public static void main(String[] args) throws IOException {
		new cfCEOI2019Day1B();
	}

	private InputStream is;
	PrintWriter out;

	private byte[] buf = new byte[1 << 14];
	private int bufSz = 0, bufPtr = 0;

	private int readByte() {
		if (bufSz == -1)
			throw new RuntimeException("Reading past EOF");
		if (bufPtr >= bufSz) {
			bufPtr = 0;
			try {
				bufSz = is.read(buf);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			if (bufSz <= 0)
				return -1;
		}
		return buf[bufPtr++];
	}

	private boolean isTrash(int c) {
		return c < 33 || c > 126;
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isTrash(b))
			;
		return b;
	}

	String nextToken() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	String nextString() {
		int b = readByte();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b) || b == ' ') {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}

	char nextChar() {
		return (char) skip();
	}

	int nextInt() {
		int ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}

	long nextLong() {
		long ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}
}


import java.io.*;
import java.math.*;
import java.util.*;
import java.util.stream.*;

public class cfCEOI2019Day1B {

	static class HLD {
		int n, root;

		private int[][] g;
		private int[] sz;
		private int timePtr = 0;

		// parent of node, time -> time
		public int[] par;

		// tree traversal, time -> node
		int[] time2Node;

		// time when you get in/out of the node
		// Subtree of v has times [ v; rgh(v) )
		int[] node2Time; // node -> time
		int[] rgh; // time -> time

		// lft and order are inverse permutations

		// depth, time -> int
		int[] depth;

		// if chainInfo[v] < 0 then v is the head of chain with id =
		// (~chainInfo[v]), time->chainId
		// if chainInfo[v] >=0 then chainInfo[v] is the head of chain that v
		// belongs to, time->time
		private int[] chainInfo;

		// top-most node of the corresponding chain, chainId -> time
		int[] chainHead;

		int chainCnt = 0;
		private int[] buf;

		public HLD(int[] vs, int[] us, int root) {
			n = vs.length + 1;
			this.root = root;
			if (vs.length != us.length) {
				throw new AssertionError("vs.length != us.length");
			}
			if (!(0 <= root && root < n)) {
				throw new AssertionError("bad root");
			}

			// Building the graph.
			int[] deg = new int[n];
			for (int i = 0; i < n - 1; i++) {
				if (!(0 <= vs[i] && vs[i] < n && 0 <= us[i] && us[i] < n && vs[i] != us[i])) {
					throw new AssertionError("bad node in edge");
				}
				deg[vs[i]]++;
				deg[us[i]]++;
			}
			g = new int[n][];
			for (int i = 0; i < n; i++) {
				g[i] = new int[deg[i]];
			}
			for (int i = 0; i < n - 1; i++) {
				int v = vs[i];
				int u = us[i];
				g[v][--deg[v]] = u;
				g[u][--deg[u]] = v;
			}

			// Find sizes/parents and reorder children.
			sz = new int[n];
			dfsSz(root, -1);

			// Find the chains/subtree ranges.
			par = new int[n];
			par[0] = -1;

			depth = new int[n];
			time2Node = new int[n];
			node2Time = new int[n];
			rgh = new int[n];

			chainHead = new int[n];
			chainHead[chainCnt] = 0;

			chainInfo = new int[n];
			chainInfo[0] = ~(chainCnt++);

			dfsChains(root, -1);

			chainHead = Arrays.copyOf(chainHead, chainCnt);
			buf = new int[3 * chainCnt];
		}

		/**
		 * @return list of triplets [chainId; pos1; pos2] in order corresponding
		 *         to the path from v to u

		 *         pos1 <= pos2 = going down

		 *         pos1 > pos2 = going up
		 */
		public int[] getPath(int v, int u) {
			int headPtr = 0, tailPtr = buf.length;
			int chV = chainId(v), upV = chainHead[chV], chU = chainId(u), upU = chainHead[chU];
			while (chV != chU) {
				if (depth[upV] > depth[upU]) {
					buf[headPtr] = chV;
					buf[headPtr + 1] = v - upV;
					buf[headPtr + 2] = 0;
					headPtr += 3;
					v = par[upV];
					chV = chainId(v);
					upV = chainHead[chV];
				} else {
					buf[tailPtr - 3] = chU;
					buf[tailPtr - 2] = 0;
					buf[tailPtr - 1] = u - upU;
					tailPtr -= 3;
					u = par[upU];
					chU = chainId(u);
					upU = chainHead[chU];
				}
			}
			int base = chainHead[chV];
			buf[headPtr] = chV;
			buf[headPtr + 1] = v - base;
			buf[headPtr + 2] = u - base;
			headPtr += 3;

			System.arraycopy(buf, tailPtr, buf, headPtr, buf.length - tailPtr);
			return Arrays.copyOf(buf, headPtr + buf.length - tailPtr);
		}

		// the length of chain #id
		// chainId -> int
		public int chainSz(int id) {
			return (id == chainHead.length - 1 ? n : chainHead[id + 1]) - chainHead[id];
		}

		// the id of chain that node belongs to
		// time -> chainId
		public int chainId(int node) {
			// if node is not a chain's head, set node to the head
			if (chainInfo[node] >= 0) {
				node = chainInfo[node];
			}
			return ~chainInfo[node];
		}

		// the position of a node within its chain
		// time -> int
		public int chainPos(int t) {
			int x = chainInfo[t];
			return x >= 0 ? t - x : 0;
		}

		// returns the NODE in the given chain at the given position
		// this is called getTime because you should only care
		// about "times" and not original node numbers
		public int getTime(int chainId, int chainPos) {
			return chainHead[chainId] + chainPos;
		}

		// time -> boolean
		public boolean isLeaf(int t) {
			return g[time2Node[t]].length == (t == 0 ? 0 : 1);
		}

		private void dfsSz(int v, int p) {
			sz[v] = 1;
			int[] adj = g[v];
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				dfsSz(u, v);
				sz[v] += sz[u];
				if (adj[0] == p || sz[u] > sz[adj[0]]) {
					adj[i] = adj[0];
					adj[0] = u;
				}
			}
		}

		private void dfsChains(int v, int p) {
			int tv = timePtr++;
			time2Node[tv] = v;
			node2Time[v] = tv;

			int[] adj = g[v];
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				par[timePtr] = tv;
				depth[timePtr] = depth[tv] + 1;
				if (i == 0) {
					chainInfo[timePtr] = chainInfo[tv] >= 0 ? chainInfo[tv] : tv;
				} else {
					chainHead[chainCnt] = timePtr;
					chainInfo[timePtr] = ~(chainCnt++);
				}
				dfsChains(u, v);
			}

			rgh[tv] = timePtr;
		}
	}

	void submit() {
		int n = nextInt();
		int q = nextInt();
		long w = nextLong();
		int[] vs = new int[n - 1];
		int[] us = new int[n - 1];
		long[] ws = new long[n - 1];
		for (int i = 0; i < n - 1; i++) {
			vs[i] = nextInt() - 1;
			us[i] = nextInt() - 1;
			ws[i] = nextLong();
		}

		HLD hld = new HLD(vs, us, 0);

		for (int i = 0; i < n - 1; i++) {
			vs[i] = hld.node2Time[vs[i]];
			us[i] = hld.node2Time[us[i]];
		}

		int[] rgh = hld.rgh;
		for (int i = 0; i < n - 1; i++) {
			if (vs[i] > us[i]) {
				int tmp = vs[i];
				vs[i] = us[i];
				us[i] = tmp;
			}
		}

		Node depths = new Node(0, n);
		for (int i = 0; i < n - 1; i++) {
			depths.addSegm(us[i], rgh[us[i]], ws[i]);
		}

		Node[] aux = new Node[hld.chainCnt];
		for (int i = 0; i < aux.length; i++) {
			aux[i] = new Node(0, hld.chainSz(i));
		}

		int[] chainHead = hld.chainHead;
		for (int v = 0; v < n; v++) {
			if (hld.isLeaf(v)) {
				continue;
			}
			int ch = hld.chainId(v);
			int pos = hld.chainPos(v);
			int head = chainHead[ch];

			long maxExceptChain = depths.getSegm(rgh[v + 1], rgh[v]);
			if (maxExceptChain < 0) {
				aux[ch].addPoint(pos, -INF);
				continue;
			}
			aux[ch].addPoint(pos, maxExceptChain + depths.getPoint(head) - 2 * depths.getPoint(v));
		}

		long last = 0;
		while (q-- > 0) {
			int edgeIdx = nextInt();
			long newW = nextLong();
			edgeIdx = (int) ((edgeIdx + last) % (n - 1));
			newW = (newW + last) % w;

			// System.err.println(edgeIdx + " " + newW);
			// System.err.println("old: " + Arrays.toString(ws));

			long oldW = ws[edgeIdx];
			long deltaW = newW - oldW;

			ws[edgeIdx] = newW;

			// System.err.println("new: " + Arrays.toString(ws));

			// update edge weight
			{
				int v = us[edgeIdx];
				depths.addSegm(v, rgh[v], deltaW);

				// update relative depth and maxRelExceptChain for nodes below v
				// on its chain
				int ch = hld.chainId(v);
				int pos = hld.chainPos(v);
				if (pos != 0) {
					aux[ch].addSegm(pos, hld.chainSz(ch), -deltaW);
				}

				// update maxRelExceptChain for last nodes on the chains
				int[] path = hld.getPath(0, v);
				for (int i = 0; i < path.length - 3; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					int vPos = path[i + 2];
					v = hld.getTime(chainId, vPos);
					long newVal = depths.getSegm(rgh[v + 1], rgh[v]) + depths.getPoint(headV)
							- 2 * depths.getPoint(v);

					aux[chainId].setPoint(vPos, newVal);
				}
			}

			long ans;

			// find diameter
			{
				int deepV = depths.maxPos();
				if (!hld.isLeaf(deepV)) {
					throw new AssertionError("deepest node must be a leaf!");
				}
				ans = depths.getPoint(deepV);
				long vDepth = ans;

				int[] path = hld.getPath(0, deepV);
				for (int i = 0; i < path.length; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					// not last node on a chain, use aux seg tree
					ans = Math.max(
							ans,
							aux[chainId].getSegm(0, path[i + 2])
									+ (vDepth - depths.getPoint(headV)));

					if (i == path.length - 3) {
						continue;
					}

					// last node on a chain
					int lastNode = hld.getTime(chainId, path[i + 2]);
					int nxtNode = chainHead[path[i + 3]];
					long deepOther = Math.max(depths.getSegm(lastNode, nxtNode),
							depths.getSegm(rgh[nxtNode], rgh[lastNode]));
					ans = Math.max(ans, deepOther + vDepth - 2 * depths.getPoint(lastNode));
				}
			}
			out.println(ans);
			last = ans;
		}
	}

	static final long INF = Long.MAX_VALUE / 3;

	static class Node {
		int l, r;
		Node left, right;
		long add, max;

		long getMax() {
			return max + add;
		}

		public Node(int l, int r) {
			this.l = l;
			this.r = r;
			if (r - l > 1) {
				int m = (l + r) >> 1;
				left = new Node(l, m);
				right = new Node(m, r);
			}
		}

		void addSegm(int ql, int qr, long delta) {
			if (l >= qr || ql >= r) {
				return;
			}
			if (ql <= l && r <= qr) {
				add += delta;
				return;
			}
			left.addSegm(ql, qr, delta);
			right.addSegm(ql, qr, delta);
			max = Math.max(left.getMax(), right.getMax());
		}

		long getSegm(int ql, int qr) {
			if (l >= qr || ql >= r) {
				return -INF;
			}
			if (ql <= l && r <= qr) {
				return getMax();
			}
			return Math.max(left.getSegm(ql, qr), right.getSegm(ql, qr)) + add;
		}

		int maxPos() {
			if (r - l == 1) {
				return l;
			}
			return left.getMax() > right.getMax() ? left.maxPos() : right.maxPos();
		}

		void setPoint(int idx, long val) {
			if (r - l == 1) {
				add = 0;
				max = val;
				return;
			}
			left.add += add;
			right.add += add;
			add = 0;
			(idx < left.r ? left : right).setPoint(idx, val);
			max = Math.max(left.getMax(), right.getMax());
		}

		void addPoint(int idx, long delta) {
			if (r - l == 1) {
				add += delta;
				return;
			}
			(idx < left.r ? left : right).addPoint(idx, delta);
			max = Math.max(left.getMax(), right.getMax());
		}

		long getPoint(int idx) {
			if (r - l == 1) {
				return getMax();
			}
			return (idx < left.r ? left : right).getPoint(idx) + add;
		}
	}

	void test() {

	}

	void stress() {
		for (int tst = 0;; tst++) {
			if (false) {
				throw new AssertionError();
			}
			System.err.println(tst);
		}
	}

	cfCEOI2019Day1B() throws IOException {
		if (System.getProperty("ONLINE_JUDGE") == null) {
			is = new FileInputStream("in.txt");
		} else {
			is = System.in;
		}
		out = new PrintWriter(System.out);
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();
	static final int C = 5;

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

	public static void main(String[] args) throws IOException {
		new cfCEOI2019Day1B();
	}

	private InputStream is;
	PrintWriter out;

	private byte[] buf = new byte[1 << 14];
	private int bufSz = 0, bufPtr = 0;

	private int readByte() {
		if (bufSz == -1)
			throw new RuntimeException("Reading past EOF");
		if (bufPtr >= bufSz) {
			bufPtr = 0;
			try {
				bufSz = is.read(buf);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			if (bufSz <= 0)
				return -1;
		}
		return buf[bufPtr++];
	}

	private boolean isTrash(int c) {
		return c < 33 || c > 126;
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isTrash(b))
			;
		return b;
	}

	String nextToken() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	String nextString() {
		int b = readByte();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b) || b == ' ') {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}

	char nextChar() {
		return (char) skip();
	}

	int nextInt() {
		int ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}

	long nextLong() {
		long ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}
}


import java.util.*;
import java.io.*;

public class G {

	public static void main(String[] args) { new G(); }

	long[] weights;
	boolean[] isDecomped;
	ArrayList<Integer>[] centroids, adj, immediateKids;

	int timeStamp, dfsTime;
	int[] bfsOrder, subSize, visited, parInBfs;
	long[] distTo;
	HashMap<Integer, Integer>[] maps;

	ST_[] sts;

	int[][] preOrder, postOrder;

	G() {
		FastScanner fs = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		System.err.println("");

		int n = fs.nextInt();
		int Q = fs.nextInt();
		long maxWeight = fs.nextLong();

		int N = n + n - 1;

		adj = new ArrayList[N];
		for(int i = 0; i < N; i++) adj[i] = new ArrayList<>();
		weights = new long[N];

		for(int i = 0; i < n-1; i++) {

			int u = fs.nextInt()-1;
			int v = fs.nextInt()-1;
			long we = fs.nextLong();

			int idx = n + i;

			adj[u].add(idx);
			adj[idx].add(u);

			adj[idx].add(v);
			adj[v].add(idx);

			weights[idx] = we;
		}

		centroids = new ArrayList[N];
		for(int i = 0; i < N; i++) {
			centroids[i] = new ArrayList<>();
		}

		isDecomped = new boolean[N];
		bfsOrder = new int[N];
		subSize = new int[N];
		visited = new int[N];
		parInBfs = new int[N];

		distTo = new long[N];
		preOrder = new int[20][N];
		postOrder = new int[20][N];

		immediateKids = new ArrayList[N];
		for(int i = 0; i < N; i++) immediateKids[i] = new ArrayList<>();

		maps = new HashMap[N];
		for(int i = 0; i < N; i++) maps[i] = new HashMap<>();

		sts = new ST_[N];

		decomp(0);

		TreeSet<p> candAnswers = new TreeSet<>();
		long[] oldAnswers = new long[N];

		for(int i = 0; i < N; i++) {
			//get some stuff

			p ans = getAnswer(i);
			if(ans != null) {
				candAnswers.add(ans);
				oldAnswers[i] = ans.val;
			}
		}

//		out.println(candAnswers.last().val + " " + candAnswers.last().idx);

		p temp = new p(-1, -1);
		long last = 0;
		for(int qq = 0; qq < Q; qq++) {

			int d = fs.nextInt();
			long e = fs.nextLong();

			int node = (int)((d + last) % (n - 1));
			node += n;

			long edgeWe = (e + last) % maxWeight;

			long delta = edgeWe - weights[node];

			for(int cent : centroids[node]) {
				//node's pre, post in cent's seg tree

				int mapIdx = maps[node].get(cent);
				int L = preOrder[mapIdx][node];
				int R = postOrder[mapIdx][node];

				sts[cent].rangeAdd(1, L, R, delta);

				//remove old pair
				temp.idx = cent; temp.val = oldAnswers[cent];
				boolean rem = candAnswers.remove(temp);

				temp = getAnswer(cent);

				candAnswers.add(new p(temp.idx, temp.val));
				oldAnswers[cent] = temp.val;
			}

			weights[node] = edgeWe;

			out.println(candAnswers.last().val);
			last = candAnswers.last().val;
		}

		out.close();
	}

	void decomp(int rt) {
		timeStamp++;

		//bfs
		int ptr = 0;
		bfsOrder[ptr++] = rt;
		visited[rt] = timeStamp;

		for(int head = 0; head < ptr; head++) {
			int u = bfsOrder[head];
			for(int v : adj[u]) {
				if(visited[v] == timeStamp) continue;
				if(isDecomped[v]) continue;

				parInBfs[v] = u;
				visited[v] = timeStamp;
				bfsOrder[ptr++] = v;
			}
		}
		for(int tail = ptr-1; tail >= 0; tail--) {
			int u = bfsOrder[tail];
			subSize[u] = 1;
			for(int v : adj[u]) {
				if(isDecomped[v]) continue;
				if(parInBfs[u] == v) continue;

				subSize[u] += subSize[v];
			}
		}

		int cent = -1;

		for(int i = 0; i < ptr; i++) {
			boolean isGood = true;
			int u = bfsOrder[i];
			for(int v : adj[u]) {
				if(isDecomped[v]) continue;

				if(parInBfs[u] == v) {
					isGood &= (ptr-subSize[u]) <= ptr/2;
				}
				else {
					isGood &= subSize[v] <= ptr/2;
				}
			}
			if(isGood) {
				cent = u;
				break;
			}
		}
		if(cent < 0) throw null; //:(

		for(int i = 0; i < ptr; i++) {
			int u = bfsOrder[i];
			centroids[u].add(cent);
		}

		dfsTime = 0;
		dfs(cent, -1, 0);

		for(int v : adj[cent]) {
			if(visited[v] == timeStamp) {
				immediateKids[cent].add(v);
			}
		}

		//make st
		sts[cent] = new ST_(ptr);

		isDecomped[cent] = true;
		for(int v : adj[cent]) {
			if(isDecomped[v]) continue;
			decomp(v);
		}
	}

	//ST[cent] = sizeSubtree

	//u -> bfsOrder
	void dfs(int u, int par, long dist) {
		int idx = centroids[u].size()-1;
		preOrder[idx][u] = dfsTime++;

		dist += weights[u];

		maps[u].put(centroids[u].get(idx), idx);
		distTo[ preOrder[idx][u] ] = dist;

		for(int v : adj[u]) if(visited[v] == timeStamp && v != par) {

			dfs(v, u, dist);

		}

		postOrder[idx][u] = dfsTime-1;
	}

	p getAnswer(int i) {
		p max1 = sts[i].rangeMax(1, 0, sts[i].R[1]);
		if(max1 == null) return null;

		long value = max1.val;

//		System.out.println("     " + i + " " + immediateKids[i]);

		int lo = 0, hi = immediateKids[i].size()-1;

		int L = -1, R = -1;

		while(lo <= hi) {
			int mid = (lo+hi) / 2;

			int thatKid = immediateKids[i].get(mid);
			int mapIdx = maps[thatKid].get(i);
			if(max1.idx <= postOrder[mapIdx][thatKid]) {

				L = preOrder[mapIdx][thatKid];
				R = postOrder[mapIdx][thatKid];

				hi = mid-1;
			}
			else {
				lo = mid+1;
			}
		}

		//get max2
		if(L >= 0) {
			p max2 = null;
			p check1 = sts[i].rangeMax(1, 1, L-1);
			p check2 = sts[i].rangeMax(1, R+1, sts[i].R[1]);

			if(check1 != null && check2 != null) {
				if(check1.val >= check2.val) max2 = check1;
				else max2 = check2;
			}
			else if(check1 == null) max2 = check2;
			else max2 = check1;

			if(max2 != null) {
				value += max2.val - sts[i].rangeMax(1, 0, 0).val;
			}
		}

		return new p(i, value);
	}

	//range max: return pair(max, idxOfMax)
	//range add

	class ST_ {
		int[] L, R, maxIdx;
		long[] delta, max;
		int size;

		ST_(int N) {
			size = 4*N+10;
			L = new int[size];
			R = new int[size];
			maxIdx = new int[size];
			delta = new long[size];
			max = new long[size];
			init(1, 0, N-1);
		}
		void init(int p, int a, int b) {
			L[p] = a; R[p] = b;
			if(a == b) {
				max[p] = distTo[a];
				maxIdx[p] = a;
				return;
			}
			int mid = (a + b) / 2;
			init(2 * p, a, mid);
			init(2 * p + 1, mid+1, b);

			update(p);
		}

		void rangeAdd(int p, int ll, int rr, long val) {
			if(rr < L[p] || R[p] < ll) return;
			if(ll <= L[p] && R[p] <= rr) {
				delta[p] += val;
				return;
			}
			prop(p);

			rangeAdd(2 * p, ll, rr, val);
			rangeAdd(2*p+1, ll, rr, val);

			update(p);
		}

		p rangeMax(int p, int ll, int rr) {
			if(rr < ll) return null;
			if(rr < L[p] || R[p] < ll) return null;
			if(ll <= L[p] && R[p] <= rr) {
				return new p(maxIdx[p], getMax(p));
			}
			prop(p);

			p lf = rangeMax(2 * p, ll, rr);
			p rg = rangeMax(2 * p + 1, ll, rr);

			update(p);

			if(lf == null) return rg;
			if(rg == null) return lf;

			if(rg.val >= lf.val) return rg;
			return lf;
		}

		void prop(int p) {
			if(delta[p] == 0) return;

			delta[2 * p] += delta[p];
			delta[2 * p + 1] += delta[p];

			delta[p] = 0;
		}

		long getMax(int p) {
			return delta[p]+max[p];
		}

		void update(int p) {
			long leftVal = getMax(2 * p);
			long rightVal = getMax(2*p+1);

			if(leftVal >= rightVal) {
				max[p] = leftVal;
				if(leftVal == rightVal)
					maxIdx[p] = maxIdx[2 * p + 1];
				else
					maxIdx[p] = maxIdx[2 * p];
			}
			else {
				max[p] = rightVal;
				maxIdx[p] = maxIdx[2 * p + 1];
			}
		}
	}

	class ST {
		ST left, right;
		int L, R;
		long delta, max;
		int maxIdx;

		ST(int a, int b) {
			L = a; R = b;

			if(a == b) {
				max = distTo[a];
				maxIdx = a;
				return;
			}

			int mid = (a + b) / 2;
			left = new ST(a, mid);
			right = new ST(mid+1, b);

			update();
		}

		void rangeAdd(int ll, int rr, long add) {
			if(rr < L || R < ll) return;
			if(ll <= L && R <= rr) {
				delta += add;
				return;
			}
			prop();

			left.rangeAdd(ll, rr, add);
			right.rangeAdd(ll, rr, add);

			update();
		}

		p rangeMax(int ll, int rr) {
			if(rr < ll) return null;
			if(rr < L || R < ll) return null;
			if(ll <= L && R <= rr) {
				return new p(maxIdx, getMax());
			}
			prop();

			p lf = left.rangeMax(ll, rr);
			p rg = right.rangeMax(ll, rr);

			update();

			if(lf == null) return rg;
			if(rg == null) return lf;

			if(rg.val >= lf.val) return rg;
			return lf;
		}

		void prop() {
			if(delta == 0) return;

			left.delta += delta;
			right.delta += delta;

			delta = 0;
		}

		long getMax() {
			return max + delta;
		}

		void update() {
			long leftVal = left.getMax();
			long rightVal = right.getMax();

			if(leftVal >= rightVal) {
				max = leftVal;
				if(leftVal == rightVal)
					maxIdx = right.maxIdx;
				else
					maxIdx = left.maxIdx;
			}
			else {
				max = rightVal;
				maxIdx = right.maxIdx;
			}
		}
	}

	class p implements Comparable<p> {
		int idx;
		long val;
		p(int i, long v) { idx = i; val = v; }
		public int compareTo(p p) {
			int comp = Long.compare(val, p.val);
			if(comp == 0) comp = Integer.compare(idx, p.idx);
			return comp;
		}
		public String toString() {
			return String.format("(%d, %d)", idx, val);
		}
	}

	static class IntList {
		static int[] EMPTY = {};
		int n = 0, a[] = EMPTY;
		void add(int v) {
			if (n >= a.length)
				a = Arrays.copyOf(a, (n << 2) + 8);
			a[n++] = v;
		}
		int get(int idx) { return a[idx]; }
		int size() { return n; }
	}

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;
		FastScanner(){
			br = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer("");
		}
		String next() {
			if(st.hasMoreTokens()) return st.nextToken();
			try { st = new StringTokenizer(br.readLine()); }
			catch (Exception e) {}
			return next();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}

}


import java.io.*;
import java.math.*;
import java.util.*;
import java.util.stream.*;

public class cfCEOI2019Day1B {

	static class HLD {
		int n, root;

		// g[v] - edges incident to node v, including the edge going up!
		int[][] g;

		// sz[v] - size of node v subree, node -> int
		int[] sz;

		// parent of node, node -> node
		int[] par;

		private int time = 0;

		// tree traversal, time -> node
		int[] order;

		// time when you get in/out of the node, node -> time
		// Subtree of v has times [ lft(v); rgh(v) )
		int[] lft, rgh;

		// lft and order are inverse permutations

		// depth, node -> int
		int[] depth;

		// if chainInfo[v] < 0 then v is the head of chain with id =
		// (~chainInfo[v]), node->chainId
		// if chainInfo[v] >=0 then chainInfo[v] is the head of chain that v
		// belongs to, node->node
		private int[] chainInfo;

		// top-most node of the corresponding chain, chainId -> node
		int[] chainHead;

		// down[v] = next node on the same chain as v, or -1 for leaves
		int[] down;

		int chainCnt = 0;
		private int[] buf;

		public HLD(int[] vs, int[] us, int root) {
			n = vs.length + 1;
			this.root = root;
			if (vs.length != us.length) {
				throw new AssertionError("vs.length != us.length");
			}
			if (!(0 <= root && root < n)) {
				throw new AssertionError("bad root");
			}

			// Building the graph.
			int[] deg = new int[n];
			for (int i = 0; i < n - 1; i++) {
				if (!(0 <= vs[i] && vs[i] < n && 0 <= us[i] && us[i] < n && vs[i] != us[i])) {
					throw new AssertionError("bad node in edge");
				}
				deg[vs[i]]++;
				deg[us[i]]++;
			}
			g = new int[n][];
			for (int i = 0; i < n; i++) {
				g[i] = new int[deg[i]];
			}
			for (int i = 0; i < n - 1; i++) {
				int v = vs[i];
				int u = us[i];
				g[v][--deg[v]] = u;
				g[u][--deg[u]] = v;
			}

			// Find sizes/parents and reorder children.
			sz = new int[n];
			par = new int[n];
			depth = new int[n];
			dfsSz(root, -1);

			// Find the chains/subtree ranges.
			order = new int[n];
			lft = new int[n];
			rgh = new int[n];
			chainInfo = new int[n];
			chainHead = new int[n];
			chainHead[chainCnt] = root;
			chainInfo[root] = ~(chainCnt++);
			down = new int[n];
			Arrays.fill(down, -1);
			dfsChains(root, -1);

			chainHead = Arrays.copyOf(chainHead, chainCnt);
			buf = new int[3 * chainCnt];
		}

		/**
		 * @return list of triplets [chainId; pos1; pos2] in order corresponding
		 *         to the path from v to u

		 *         pos1 <= pos2 = going down

		 *         pos1 > pos2 = going up
		 */
		public int[] getPath(int v, int u) {
			int headPtr = 0, tailPtr = buf.length;
			int chV = chainId(v), chU = chainId(u);
			while (chV != chU) {
				int upV = chainHead[chV];
				int upU = chainHead[chU];
				if (depth[upV] > depth[upU]) {
					buf[headPtr] = chV;
					buf[headPtr + 1] = lft[v] - lft[upV];
					buf[headPtr + 2] = 0;
					headPtr += 3;
					v = par[upV];
					chV = chainId(v);
				} else {
					buf[tailPtr - 3] = chU;
					buf[tailPtr - 2] = 0;
					buf[tailPtr - 1] = lft[u] - lft[upU];
					tailPtr -= 3;
					u = par[upU];
					chU = chainId(u);
				}
			}
			int base = lft[chainHead[chV]];
			buf[headPtr] = chV;
			buf[headPtr + 1] = lft[v] - base;
			buf[headPtr + 2] = lft[u] - base;
			headPtr += 3;

			System.arraycopy(buf, tailPtr, buf, headPtr, buf.length - tailPtr);
			return Arrays.copyOf(buf, headPtr + buf.length - tailPtr);
		}

		// the length of chain #id
		// chainId -> int
		public int chainSz(int id) {
			return (id == chainHead.length - 1 ? n : lft[chainHead[id + 1]]) - lft[chainHead[id]];
		}

		// the id of chain that node belongs to
		// node -> chainId
		public int chainId(int node) {
			// if node is not a chain's head, set node to the head
			if (chainInfo[node] >= 0) {
				node = chainInfo[node];
			}
			return ~chainInfo[node];
		}

		// the position of a node within its chain
		// node -> int
		public int chainPos(int node) {
			int x = chainInfo[node];
			return x >= 0 ? lft[node] - lft[x] : 0;
		}

		// (chainId, int) -> node
		public int getNode(int chainId, int chainPos) {
			if (!(0 <= chainId && chainId < chainCnt)) {
				throw new AssertionError("bad chainId");
			}
			if (!(0 <= chainPos && chainPos < chainSz(chainId))) {
				throw new AssertionError("bad chainPos");
			}
			return order[lft[chainHead[chainId]] + chainPos];
		}

		private void dfsSz(int v, int p) {
			sz[v] = 1;
			int[] adj = g[v];
			par[v] = p;
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				depth[u] = depth[v] + 1;
				dfsSz(u, v);
				sz[v] += sz[u];
				if (adj[0] == p || sz[u] > sz[adj[0]]) {
					adj[i] = adj[0];
					adj[0] = u;
				}
			}
		}

		private void dfsChains(int v, int p) {
			order[time] = v;
			lft[v] = time++;

			int[] adj = g[v];
			for (int i = 0; i < adj.length; i++) {
				int u = adj[i];
				if (u == p) {
					continue;
				}
				if (i == 0) {
					down[v] = u;
					chainInfo[u] = chainInfo[v] >= 0 ? chainInfo[v] : v;
				} else {
					chainHead[chainCnt] = u;
					chainInfo[u] = ~(chainCnt++);
				}
				dfsChains(u, v);
			}

			rgh[v] = time;
		}
	}

	void submit() {
		int n = nextInt();
		int q = nextInt();
		long w = nextLong();
		int[] vs = new int[n - 1];
		int[] us = new int[n - 1];
		long[] ws = new long[n - 1];
		for (int i = 0; i < n - 1; i++) {
			vs[i] = nextInt() - 1;
			us[i] = nextInt() - 1;
			ws[i] = nextLong();
		}

		HLD hld = new HLD(vs, us, 0);

		int[] depth = hld.depth;
		int[] lft = hld.lft;
		int[] rgh = hld.rgh;
		for (int i = 0; i < n - 1; i++) {
			if (depth[vs[i]] > depth[us[i]]) {
				int tmp = vs[i];
				vs[i] = us[i];
				us[i] = tmp;
			}
		}

		SegTree depths = new SegTree(n);
		for (int i = 0; i < n - 1; i++) {
			depths.addSegment(lft[us[i]], rgh[us[i]], ws[i]);
		}

		SegTree[] aux = new SegTree[hld.chainCnt];
		for (int i = 0; i < aux.length; i++) {
			aux[i] = new SegTree(hld.chainSz(i));
		}

		int[] chainHead = hld.chainHead;
		int[] down = hld.down;
		for (int v = 0; v < n; v++) {
			if (down[v] == -1) {
				continue;
			}
			int ch = hld.chainId(v);
			int pos = hld.chainPos(v);
			int head = chainHead[ch];

			long vDepth = depths.getPoint(lft[v]);
			long headDepth = depths.getPoint(lft[head]);
			long maxExceptChain = depths.getSegment(rgh[down[v]], rgh[v]);
			if (maxExceptChain < 0) {
				aux[ch].addPoint(pos, -INF);
				continue;
			}
			aux[ch].addPoint(pos, maxExceptChain - headDepth - 2 * (vDepth - headDepth));
		}

		int[] order = hld.order;

		long last = 0;
		while (q-- > 0) {
			int edgeIdx = nextInt();
			long newW = nextLong();
			edgeIdx = (int) ((edgeIdx + last) % (n - 1));
			newW = (newW + last) % w;

//			System.err.println(edgeIdx + " " + newW);
//			System.err.println("old: " + Arrays.toString(ws));

			long oldW = ws[edgeIdx];
			long deltaW = newW - oldW;

			ws[edgeIdx] = newW;

//			System.err.println("new: " + Arrays.toString(ws));

			// update edge weight
			{
				int v = us[edgeIdx];
				depths.addSegment(lft[v], rgh[v], deltaW);

				// update relative depth and maxRelExceptChain for nodes below v on its chain
				int ch = hld.chainId(v);
				int pos = hld.chainPos(v);
				aux[ch].addSegment(pos, hld.chainSz(ch), -deltaW);

				// update maxRelExceptChain for last nodes on the chains
				int[] path = hld.getPath(0, v);
				for (int i = 0; i < path.length - 3; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					int vPos = path[i + 2];
					v = hld.getNode(chainId, vPos);
					long headDepth = depths.getPoint(lft[headV]);
					long newVal = depths.getSegment(rgh[down[v]], rgh[v])
							- headDepth - 2 * (depths.getPoint(lft[v]) - headDepth);

					aux[chainId].setPoint(vPos, newVal);
				}
			}

			long ans;

			// find diameter
			{
				int deepVTime = depths.maxPos();
				int deepV = order[deepVTime]; // not just maxPos !!!
				if (down[deepV] != -1) {
					throw new AssertionError("deepest node must be a leaf!");
				}
				ans = depths.getPoint(deepVTime);
				long vDepth = ans;

				int[] path = hld.getPath(0, deepV);
				for (int i = 0; i < path.length; i += 3) {
					int chainId = path[i];
					int headV = chainHead[chainId];
					// not last node on a chain, use aux seg tree
					ans = Math.max(
							ans,
							aux[chainId].getSegment(0, path[i + 2])
									+ (vDepth - depths.getPoint(lft[headV])));

					if (i == path.length - 3) {
						continue;
					}

					// last node on a chain
					int lastNode = hld.getNode(chainId, path[i + 2]);
					int nxtNode = chainHead[path[i + 3]];
					long deepOther = Math.max(depths.getSegment(lft[lastNode], lft[nxtNode]),
							depths.getSegment(rgh[nxtNode], rgh[lastNode]));
					ans = Math.max(ans, deepOther + vDepth - 2 * depths.getPoint(lft[lastNode]));
				}
			}
			out.println(ans);
			last = ans;
		}
	}

	static final long INF = Long.MAX_VALUE / 3;

	// TODO: check with local parameters/without SegTree class at all?
	static class SegTree {
		static int ql, qr;
		static long delta;
		Node root;

		public SegTree(int n) {
			root = new Node(0, n);
		}

		public void addSegment(int ql, int qr, long delta) {
			if (ql == qr) {
				return;
			}
			if (ql > qr) {
				throw new AssertionError("ql > qr");
			}
			SegTree.ql = ql;
			SegTree.qr = qr;
			SegTree.delta = delta;
			root.add();
		}

		// TODO: can improve!
		public void addPoint(int idx, long delta) {
			addSegment(idx, idx + 1, delta);
		}

		public long getSegment(int ql, int qr) {
			if (ql == qr) {
				return -INF;
			}
			if (ql > qr) {
				throw new AssertionError("ql > qr");
			}
			SegTree.ql = ql;
			SegTree.qr = qr;
			return root.get();
		}

		public void setPoint(int idx, long val) {
			ql = idx;
			delta = val;
			root.setPoint();
		}

		// TODO: can improve!
		public long getPoint(int idx) {
			return getSegment(idx, idx + 1);
		}

		public int maxPos() {
			return root.maxPos();
		}

		static class Node {
			int l, r;
			Node left, right;
			long add, max;

			long getMax() {
				return max + add;
			}

			public Node(int l, int r) {
				this.l = l;
				this.r = r;
				if (r - l > 1) {
					int m = (l + r) >> 1;
					left = new Node(l, m);
					right = new Node(m, r);
				}
			}

			void add() {
				if (l >= qr || ql >= r) {
					return;
				}
				if (ql <= l && r <= qr) {
					add += delta;
					return;
				}
				left.add();
				right.add();
				max = Math.max(left.getMax(), right.getMax());
			}

			long get() {
				if (l >= qr || ql >= r) {
					return -INF;
				}
				if (ql <= l && r <= qr) {
					return getMax();
				}
				return Math.max(left.get(), right.get()) + add;
			}

			int maxPos() {
				if (r - l == 1) {
					return l;
				}
				return left.getMax() > right.getMax() ? left.maxPos() : right.maxPos();
			}

			void setPoint() {
				if (r - l == 1) {
					add = 0;
					max = delta;
					return;
				}
				left.add += add;
				right.add += add;
				add = 0;
				(ql < left.r ? left :right).setPoint();
				max = Math.max(left.getMax(), right.getMax());
			}
		}
	}

	void test() {

	}

	void stress() {
		for (int tst = 0;; tst++) {
			if (false) {
				throw new AssertionError();
			}
			System.err.println(tst);
		}
	}

	cfCEOI2019Day1B() throws IOException {
		if (System.getProperty("ONLINE_JUDGE") == null) {
			is = new FileInputStream("in.txt");
		} else {
			is = System.in;
		}
		out = new PrintWriter(System.out);
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();
	static final int C = 5;

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

	public static void main(String[] args) throws IOException {
		new cfCEOI2019Day1B();
	}

	private InputStream is;
	PrintWriter out;

	private byte[] buf = new byte[1 << 14];
	private int bufSz = 0, bufPtr = 0;

	private int readByte() {
		if (bufSz == -1)
			throw new RuntimeException("Reading past EOF");
		if (bufPtr >= bufSz) {
			bufPtr = 0;
			try {
				bufSz = is.read(buf);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			if (bufSz <= 0)
				return -1;
		}
		return buf[bufPtr++];
	}

	private boolean isTrash(int c) {
		return c < 33 || c > 126;
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isTrash(b))
			;
		return b;
	}

	String nextToken() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	String nextString() {
		int b = readByte();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b) || b == ' ') {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}

	char nextChar() {
		return (char) skip();
	}

	int nextInt() {
		int ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}

	long nextLong() {
		long ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}
}


import java.util.*;
public class Q869A
{
	public static void main(String asd[])
	{
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int a[]=new int [n];
		int b[]=new int [n];
		for(int x=0;x<n;x++)
		{
			a[x]=sc.nextInt();
		}
		for(int x=0;x<n;x++)
		{
		b[x]=sc.nextInt();
		}
		int counter=0;
		for(int x=0;x<n;x++)
		{
			for(int y=0;y<n;y++)
			{
			 if(Q869A.in(a[x]^b[y],a,b))
			 {
			 counter++;
			 break;
			 }
			}
		}
		if(counter%2==0)
		{
		System.out.println("Karen");
		}
		else
		{
		System.out.println("Koyomi");
		}

	}
	boolean in(int num,int a[],int b[])
	{
		for(int x=0;x<a.length;x++)
		{
		if(num==a[x])
		{
		return true;
		}
		}
		for(int x=0;x<b.length;x++)
		{
		if(num==b[x])
		{
		return true;
		}
		}
		return false;
	}
}


public class test
{

	public static int Main()
	{
	  int n;
	  n = Integer.parseInt(ConsoleInput.readToWhiteSpace(true));

	  set<Long> s = new set<Long>();

	  vector<Long> x = new vector<Long>();
	  for (int i = 0; i < n; i++)
	  {

		long xi;
		xi = Long.parseLong(ConsoleInput.readToWhiteSpace(true));
		x.push_back(xi);
		s.insert(xi);
	  }

	  vector<Long> y = new vector<Long>();
	  for (int i = 0; i < n; i++)
	  {

		long yi;
		yi = Long.parseLong(ConsoleInput.readToWhiteSpace(true));
		y.push_back(yi);
		s.insert(yi);
	  }

	  long counter = 0;
	  for (int i = 0; i < n; i++)
	  {
		for (int j = 0; j < n; j++)
		{

		  long xxy = x[i] ^ y[j];
		  if (s.count(xxy) > 0)
		  {
			counter++;
		  }
		}
	  }

	  if (counter % 2 == 0)
	  {
		System.out.print("Karen");
		System.out.print("\n");
	  }
	  else
	  {
		System.out.print("Koyomi");
		System.out.print("\n");
	  }

	  return 0;
	}
}


import  java.util.*;
import java.io.*;

public class A
{
   public static void main(String args[])
   {

               System.out.print("Karen");

       }
       catch(Exception e)
       {
           System.out.println("WHY?");
       }

   }
}


import java.util.*;
public class Q869A
{
	public static void main(String asd[])
	{
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int a[]=new int [n];
		int b[]=new int [n];
		for(int x=0;x<n;x++)
		{
			a[x]=sc.nextInt();
		}
		for(int x=0;x<n;x++)
		{
		b[x]=sc.nextInt();
		}
		int counter=0;
		for(int x=0;x<n;x++)
		{
			for(int y=0;y<n;y++)
			{
			 if(Q869A.in(a[x]^b[y],a,b))
			 {
			 counter++;
			 }
			}
		}
		if(counter%2==0)
		{
		System.out.println("Karen");
		}
		else
		{
		System.out.println("Koyomi");
		}

	}
	boolean in(int num,int a[],int b[])
	{
		for(int x=0;x<a.length;x++)
		{
		if(num==a[x])
		{
		return true;
		}
		}
		for(int x=0;x<b.length;x++)
		{
		if(num==b[x])
		{
		return true;
		}
		}
		return false;
	}
}


import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int M = scanner.nextInt();
        TreeMap<Integer,Integer> map = new TreeMap<>();
        int sum = 0;
        for(int i = 0; i < n; i++){
            int m = scanner.nextInt();
            sum += m;
            if(sum <= M){
                System.out.print(0+" ");
            }
            else{
                int diff = sum - M;
                int count = 0;
                Integer last = map.lastKey();

                int lastCount = map.get(last);
                while(diff > 0){
                    //System.out.println(last);

                    if(lastCount == 1){
                        diff -= last;
                        count++;
                    }
                    else{
                        int possibleCount = diff/last < 1 ? 1 : diff/last;
                        //System.out.println(diff+" "+last);
                        if(lastCount >= possibleCount){
                            count += possibleCount;
                            diff -= last*possibleCount;
                        }
                        else{
                            count += lastCount;
                            diff -= last*lastCount;
                        }
                    }
                    last = map.lowerKey(last);
                    if(last != null){
                        lastCount = map.get(last);
                    }

                }
                System.out.print(count+" ");
            }
            if(map.containsKey(m)){
                map.put(m,map.get(m)+1);
            }
            else{
                map.put(m,1);
            }
           // print(map);
        }
    }
    public static void print(TreeMap<Integer,Integer> map){
        Integer key = map.lastKey();
        while(key != null){
            System.out.print(key+" ");
            key = map.lowerKey(key);
        }
        System.out.println();
    }
}


package practiceProblems;

import java.util.Scanner;
import java.util.Arrays;

public class problem1185C1 {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);

		int n = sc.nextInt();

		int t = sc.nextInt();

		int a[] = new int[n];

		for(int i=0; i<n; i++) {
			a[i] = sc.nextInt();
		}

		int ans[] = new int[n];
		ans[0] = 0;

		// Calculate ans for each element
		for(int i=1; i<n; i++) {
			// for each element create temp array of sorted elements before it

			int temp[] = new int[i];
			for(int j=0; j<i; j++) {
				temp[j] = a[j];
			}

			Arrays.sort(temp);

			int currentAns = 0;
			int currentElement = i-1;
			int totalSum = 0;

			for(int j=0; j<=i; j++) {
				totalSum = totalSum + a[j];
			}

			while(totalSum > t) {
				totalSum = totalSum - temp[currentElement];
				currentAns++;
				currentElement--;
			}

			ans[i] = currentAns;

		}

		for(int i=0; i<n; i++) {
			System.out.print(ans[i] + " ");
		}
		System.out.println();

	}

}


/*package whatever //do not write package name here */

import java.io.*;
import java.util.*;
public class Omparator implements Comparator<Integer>{

            // Overriding compare()method of Comparator
                        // for descending order of cgpa
            public int compare(Integer s1, Integer s2) {
                if (s1< s2)
                    return 1;
                else if (s1 > s2)
                    return -1;
                                return 0;
                }
        }
public class Solution {

	public static void main (String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int[] a = new int[n];
		int[] su = new int[n];
		for(int i=0;i<n;++i){
		    a[i] = sc.nextInt();
		}
		int count = 0;
		int sum = 0;
		int temp =0;
		int k =0 ;
		su[0] = a[0];
		for(int i=1;i<n;++i){
		    su[i]=su[i-1]+a[i];
		}
		PriorityQueue<Integer> pq = new PriorityQueue<>(new Omparator());
		for(int i =0;i<n;++i){
		    count = 0;
		    if(su[i]>m && i!=0  ){
		        pq = new PriorityQueue<>(new Omparator());
		        temp = i;
		        for(int j = 0;j<temp;++j){
		            pq.add(a[j]);
		        }
		        while(su[i]>m && !pq.isEmpty()){
		            k = pq.remove();
		            su[i] = su[i] - k;

		            count++;
		        }
		        System.out.print(count+" ");
		    }else{
		        System.out.print("0 ");
		    }
		}
	}
}


//When I wrote this code, only God & I understood what it did. Now only God knows !!

import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.io.*;
import java.math.*;
public class Main implements Runnable {
    @Override
    public void run() {
        FastReader fr = new FastReader();
        PrintWriter pw = new PrintWriter(System.out);
        /*

         */

        pw.flush();
        pw.close();
    }

    static class FastReader
    {
        private InputStream mIs;private byte[] buf = new byte[1024];private int curChar,numChars;public FastReader() { this(System.in); }public FastReader(InputStream is) { mIs = is;}
        public int read() {if (numChars == -1) throw new InputMismatchException();if (curChar >= numChars) {curChar = 0;try { numChars = mIs.read(buf);} catch (IOException e) { throw new InputMismatchException();}if (numChars <= 0) return -1; }return buf[curChar++];}
        public String nextLine(){int c = read();while (isSpaceChar(c)) c = read();StringBuilder res = new StringBuilder();do {res.appendCodePoint(c);c = read();}while (!isEndOfLine(c));return res.toString() ;}
        public String next(){int c = read();while (isSpaceChar(c)) c = read();StringBuilder res = new StringBuilder();do {res.appendCodePoint(c);c = read();}while (!isSpaceChar(c));return res.toString();}
        public long l(){int c = read();while (isSpaceChar(c)) c = read();int sgn = 1;if (c == '-') { sgn = -1 ; c = read() ; }long res = 0; do{ if (c < '0' || c > '9') throw new InputMismatchException();res *= 10 ; res += c - '0' ; c = read();}while(!isSpaceChar(c));return res * sgn;}
        public int i(){int c = read() ;while (isSpaceChar(c)) c = read();int sgn = 1;if (c == '-') { sgn = -1 ; c = read() ; }int res = 0;do{if (c < '0' || c > '9') throw new InputMismatchException();res *= 10 ; res += c - '0' ; c = read() ;}while(!isSpaceChar(c));return res * sgn;}
        public double d() throws IOException {return Double.parseDouble(next()) ;}
        public boolean isSpaceChar(int c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1; }
        public boolean isEndOfLine(int c) { return c == '\n' || c == '\r' || c == -1; }
        public void scanIntArr(int [] arr){ for(int li=0;li<arr.length;++li){ arr[li]=i();}}
        public void scanLongArr(long [] arr){for (int i=0;i<arr.length;++i){arr[i]=l();}}
        public void shuffle(int [] arr){ for(int i=arr.length;i>0;--i) { int r=(int)(Math.random()*i); int temp=arr[i-1]; arr[i-1]=arr[r]; arr[r]=temp; } }
    }

    public static int mod = (int) (1e9 + 7);
    public static void main(String[] args) throws IOException {
        // new Thread(null,new Main(),"Anything",1<<27).start();

        FastReader fr = new FastReader();
        PrintWriter pw = new PrintWriter(System.out);
        /*
inputCopy
7 15
1 2 3 4 5 6 7
outputCopy
0 0 0 0 0 2 3
inputCopy
5 100
80 40 40 40 60
outputCopy
0 1 1 2 3
      */
            int n=fr.i();
            int m=fr.i();
            Candidate [] candidates=new Candidate[n];
            for(int ni=0;ni<n;++ni)
            {
                candidates[ni]=new Candidate(fr.i(),ni);
            }
            PriorityQueue<Candidate> pq=new PriorityQueue<>();
            int curTime=0;
            int ans=0;
            for(int i=0;i<candidates.length;++i)
            {
                if(curTime+candidates[i].t<=m)
                {
                    candidates[i].ans=ans;
                    curTime+=candidates[i].t;
                    pq.add(candidates[i]);
                }
                else
                {
                    while(pq.size()>=0)
                    {
                        curTime-=pq.remove().t;
                        ++ans;
                        if(curTime+candidates[i].t<=m)
                            break;
                    }
                    pq.add(candidates[i]);
                    curTime+=candidates[i].t;
                    //System.err.println("ans="+ans+"i="+i+" curTime="+curTime);
                    candidates[i].ans=ans;
                }
            }
            for(Candidate c:candidates)
                pw.print(c.ans+" ");
            pw.flush();
            pw.close();
    }
    public static class Candidate implements Comparable<Candidate>
    {
        int t;
        int id;
        int ans;
        public Candidate(int t, int id) {
            this.t = t;
            this.id = id;
        }

        @Override
        public int compareTo(@NotNull Main.Candidate candidate) {
            return Integer.compare(this.t,candidate.t)*-1;
        }
    }
}


import java.io.*;
import java.math.*;
import java.util.*;

public class E {

	static final int[] DX = { -1, 0, 1, 0 };
	static final int[] DY = { 0, -1, 0, 1 };

	static final int P = 1_000_000_007;

	int[] cacheInv = new int[10_000];
	{
		cacheInv[1] = 1;
		for (int i = 2; i < cacheInv.length; i++) {
			cacheInv[i] = P - (int) ((long) (P / i) * cacheInv[P % i] % P);
		}
	}

	int inv(int x) {
		if (x < cacheInv.length) {
			return cacheInv[x];
		}
		return P - (int) ((long) (P / x) * inv(P % x) % P);
	}

	void submit() {
		int r = nextInt();
		int[] byDir = new int[4];
		int sum = 0;
		for (int i = 0; i < 4; i++) {
			byDir[i] = nextInt();
			sum += byDir[i];
		}

		int invSum = inv(sum);

		for (int i = 0; i < 4; i++) {
			byDir[i] = (int) ((long) byDir[i] * invSum % P);
		}

		int s = 2 * r + 3;

		int[][] f = new int[s][s];
		int[] cx = new int[s * s];
		int[] cy = new int[s * s];
		int vars = 0;
		for (int i = 0; i < s; i++) {
			for (int j = 0; j < s; j++) {
				int sum2 = (i - r - 1) * (i - r - 1) + (j - r - 1)
						* (j - r - 1);
				if (sum2 <= r * r) {
					cx[vars] = i;
					cy[vars] = j;
					f[i][j] = vars++;
				} else {
					f[i][j] = -1;
				}
			}
		}

		int band = 0;

		for (int i = 0; i < vars; i++) {
			int x0 = cx[i];
			int y0 = cy[i];
			for (int dir = 0; dir < 4; dir++) {
				int x1 = x0 + DX[dir];
				int y1 = y0 + DY[dir];
				if (f[x1][y1] == -1) {
					continue;
				}
				int j = f[x1][y1];
				band = Math.max(band, Math.abs(i - j));
			}
		}

		int[][] bandM = new int[vars][2 * band + 1];

		for (int i = 0; i < vars; i++) {
			int x0 = cx[i];
			int y0 = cy[i];
			for (int dir = 0; dir < 4; dir++) {
				int x1 = x0 + DX[dir];
				int y1 = y0 + DY[dir];
				if (f[x1][y1] == -1) {
					continue;
				}
				int j = f[x1][y1];

				updateBandedMatrix(i, j, band, bandM, byDir[dir]);

			}
		}

		for (int i = 0; i < vars; i++) {
			for (int d = 0; d <= 2 * band; d++) {
				int j = i + d - band;
				bandM[i][d] = (i == j ? 1 : 0) - bandM[i][d];
				if (bandM[i][d] < 0) {
					bandM[i][d] += P;
				}
			}
		}

		int[] ans = inverseBanded(bandM, band, f[r + 1][r + 1]);

		int ret = 0;
		for (int x : ans) {
			ret += x;
			if (ret >= P) {
				ret -= P;
			}
		}

		out.println(ret);

	}

	void updateBandedMatrix(int row, int col, int width, int[][] m, double delta) {
		if (Math.abs(row - col) > width) {
			throw new AssertionError();
		}
		m[row][col - row + width] += delta;
	}

	int[] inverseBanded(int[][] a, int w, int whatCol) {
		int n = a.length;
		if (whatCol > n) {
			throw new AssertionError();
		}
		int[] b = new int[n];
		b[whatCol] = 1;

		for (int j = 0; j < n; j++) {
			int[] aj = a[j];
			for (int i = j + 1; i <= j + w && i < n; i++) {
				int[] ai = a[i];
				int coef = (int) ((long) ai[j - i + w] * inv(aj[w]) % P);

				for (int k = j + 1; k < n && k <= j + w; k++) {
					ai[k - i + w] -= (int) ((long) aj[k - j + w] * coef % P);
					if (ai[k - i + w] < 0) {
						ai[k - i + w] += P;
					}
				}
				b[i] -= (int) ((long) b[j] * coef % P);
				if (b[i] < 0) {
					b[i] += P;
				}
			}
		}

		for (int i = n - 1; i >= 0; i--) {
			for (int j = i + 1; j < n && j <= i + w; j++) {
				int coef = a[i][j - i + w];
				b[i] -= (int) ((long) b[j] * coef % P);
				if (b[i] < 0) {
					b[i] += P;
				}
			}
			b[i] = (int)((long)b[i] * inv(a[i][w]) % P);
		}

		return b;
	}

	void preCalc() {

	}

	void test() {

	}

	void stress() {
		for (int tst = 0;; tst++) {
			if (false) {
				throw new AssertionError();
			}
			System.err.println(tst);
		}
	}

	E() throws IOException {
		is = System.in;
		out = new PrintWriter(System.out);
		preCalc();
		submit();
		// stress();
		// test();
		out.close();
	}

	static final Random rng = new Random();
	static final int C = 5;

	static int rand(int l, int r) {
		return l + rng.nextInt(r - l + 1);
	}

	public static void main(String[] args) throws IOException {
		new E();
	}

	private InputStream is;
	PrintWriter out;

	private byte[] buf = new byte[1 << 14];
	private int bufSz = 0, bufPtr = 0;

	private int readByte() {
		if (bufSz == -1)
			throw new RuntimeException("Reading past EOF");
		if (bufPtr >= bufSz) {
			bufPtr = 0;
			try {
				bufSz = is.read(buf);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			if (bufSz <= 0)
				return -1;
		}
		return buf[bufPtr++];
	}

	private boolean isTrash(int c) {
		return c < 33 || c > 126;
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isTrash(b))
			;
		return b;
	}

	String nextToken() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	String nextString() {
		int b = readByte();
		StringBuilder sb = new StringBuilder();
		while (!isTrash(b) || b == ' ') {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	double nextDouble() {
		return Double.parseDouble(nextToken());
	}

	char nextChar() {
		return (char) skip();
	}

	int nextInt() {
		int ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}

	long nextLong() {
		long ret = 0;
		int b = skip();
		if (b != '-' && (b < '0' || b > '9')) {
			throw new InputMismatchException();
		}
		boolean neg = false;
		if (b == '-') {
			neg = true;
			b = readByte();
		}
		while (true) {
			if (b >= '0' && b <= '9') {
				ret = ret * 10 + (b - '0');
			} else {
				if (b != -1 && !isTrash(b)) {
					throw new InputMismatchException();
				}
				return neg ? -ret : ret;
			}
			b = readByte();
		}
	}
}